Skip to content

Commit

Permalink
feat: socket: support reads the next line keeping the end-of-line cha…
Browse files Browse the repository at this point in the history
…racter

Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
  • Loading branch information
zhaojh329 committed Nov 18, 2023
1 parent b5b82fb commit 1bc6bc0
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 41 deletions.
22 changes: 7 additions & 15 deletions bufio.lua
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ function methods:readfull(n, timeout)
return concat(data)
end

-- Reads a single line, not including the end-of-line bytes("\r\n" or "\n").
function methods:readline(timeout)
-- Reads a single line
function methods:readline(timeout, keep)
local reader = self.reader
local b = self.b

Expand All @@ -163,20 +163,12 @@ function methods:readline(timeout)
while true do
local idx = b:index(0x0a) -- '\n'
if idx > -1 then
local line
data[#data + 1] = b:read(idx)

if idx > 0 then
line = b:read(idx)
end

b:skip(1)

if line then
if str_sub(line, #line) == '\r' then
line = str_sub(line, 1, #line - 1)
end

data[#data + 1] = line
if keep then
data[#data + 1] = b:read(1)
else
b:skip(1)
end

return concat(data)
Expand Down
19 changes: 10 additions & 9 deletions http/client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ local function send_http_request(sock, method, path, headers, body)
end

local function recv_status_line(sock, timeout)
local data, err = sock:recv('*l', timeout)
local data, err = sock:recv('l', timeout)
if not data then
return nil, err
end

local code, status = data:match('^HTTP/1.1%s*(%d+)%s*(.*)')
local code, status = data:match('^HTTP/1.1 +(%d+) +([%w%p ]*)\r?$')
if not code or not status then
return nil, 'invalid http status line'
end
Expand All @@ -108,14 +108,14 @@ local function recv_http_headers(sock, timeout)
local headers = {}

while true do
local data, err = sock:recv('*l', timeout)
local data, err = sock:recv('l', timeout)
if not data then
return nil, err
end

if data == '' then break end
if data == '\r' or data == '' then break end

local name, value = data:match('([^%s:]+)%s*:%s*([^\r]+)')
local name, value = data:match('([%w%p]+) *: *([%w%p ]+)\r?$')
if not name or not value then
return nil, 'invalid http header'
end
Expand Down Expand Up @@ -158,12 +158,13 @@ local function receive_chunked_body(resp, sock, timeout, body_to_fd)

while true do
-- first read chunk size
local data, err = sock:recv('*l', deadtime and deadtime - sys.uptime())
local data, err = sock:recv('l', deadtime and deadtime - sys.uptime())
if not data then
return nil, err
end

if not data:match('^%x+$') then
data = data:match('^%x+\r?')
if not data then
return nil, 'not a vaild http chunked body'
end

Expand All @@ -177,7 +178,7 @@ local function receive_chunked_body(resp, sock, timeout, body_to_fd)
end

-- second read chunk data
local data, err = sock:recvfull(chunk_size, deadtime and deadtime - sys.uptime())
data, err = sock:recvfull(chunk_size, deadtime and deadtime - sys.uptime())
if not data then
return nil, err
end
Expand All @@ -188,7 +189,7 @@ local function receive_chunked_body(resp, sock, timeout, body_to_fd)
body[#body + 1] = data
end

data, err = sock:recv('*l', deadtime and deadtime - sys.uptime())
data, err = sock:recv('l', deadtime and deadtime - sys.uptime())
if not data then
return nil, err
end
Expand Down
10 changes: 5 additions & 5 deletions http/server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ local function handle_connection(con, handler)
local method, path, major_version, minor_version

while true do
local data, err = sock:recv('*l', http_keepalive > 0 and http_keepalive or read_timeout)
local data, err = sock:recv('l', http_keepalive > 0 and http_keepalive or read_timeout)
if not data then
if err == 'closed' then
log.debug(log_prefix .. err)
Expand All @@ -617,7 +617,7 @@ local function handle_connection(con, handler)
end

if #data > 0 then
method, path, major_version, minor_version = data:match('^(%u+)%s+(%S+)%s+HTTP/(%d+)%.(%d+)$')
method, path, major_version, minor_version = data:match('^(%u+) +([%w%p]+) +HTTP/(%d+)%.(%d+)\r?$')
if not method or not path or not major_version or not minor_version then
log.err(log_prefix .. 'not a vaild http request start line')
return false
Expand All @@ -640,17 +640,17 @@ local function handle_connection(con, handler)
local headers = {}

while true do
local data, err = sock:recv('*l', read_timeout)
local data, err = sock:recv('l', read_timeout)
if not data then
log.err(log_prefix .. 'not a complete http request: ' .. err)
return false
end

if data == '' then
if data == '\r' or data == '' then
break
end

local name, value = data:match('^([%w-_]+):%s*(.+)$')
local name, value = data:match('([%w%p]+) *: *([%w%p ]+)\r?$')
if not name or not value then
log.err(log_prefix .. 'not a vaild http header: ' .. data)
return false
Expand Down
21 changes: 15 additions & 6 deletions socket.lua
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ end
If a non-number-like string argument is specified, then it is interpreted as a
"pattern". The following patterns are supported:
'*a': reads from the socket until the connection is closed.
'*l': reads a line of text from the socket. Not including the end-of-line bytes("\r\n" or "\n").
'a': reads from the socket until the connection is closed.
'l': reads the next line skipping the end of line from the socket.
'L': reads the next line keeping the end-of-line character (if present) from the socket.
If no argument is specified, then it is assumed to be the pattern '*l', that is, the line reading pattern.
If no argument is specified, then it is assumed to be the pattern 'l', that is, the line reading pattern.
--]]
local function sock_recv(sock, pattern, timeout)
local fd = sock.fd
Expand All @@ -106,7 +107,11 @@ local function sock_recv(sock, pattern, timeout)
return b:read(pattern, timeout)
end

if pattern == '*a' then
if pattern and str_sub(pattern, 1, 1) == '*' then
pattern = str_sub(pattern, 2)
end

if pattern == 'a' then
local data = {}
local chunk, err
while true do
Expand All @@ -126,8 +131,12 @@ local function sock_recv(sock, pattern, timeout)
return nil, err, concat(data)
end

if not pattern or pattern == '*l' then
return b:readline(timeout)
if not pattern then
pattern = 'l'
end

if pattern == 'l' or pattern == 'L' then
return b:readline(timeout, pattern == 'L')
end

error('invalid pattern:' .. tostring(pattern))
Expand Down
14 changes: 11 additions & 3 deletions ssl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,11 @@ function client_methods:recv(pattern, timeout)
return b:read(pattern, timeout)
end

if pattern == '*a' then
if pattern and str_sub(pattern, 1, 1) == '*' then
pattern = str_sub(pattern, 2)
end

if pattern == 'a' then
local data = {}
local chunk, err
while true do
Expand All @@ -160,8 +164,12 @@ function client_methods:recv(pattern, timeout)
return nil, err, concat(data)
end

if not pattern or pattern == '*l' then
return b:readline(timeout)
if not pattern then
pattern = 'l'
end

if pattern == 'l' or pattern == 'L' then
return b:readline(timeout, pattern == 'L')
end

error('invalid pattern:' .. tostring(pattern))
Expand Down
14 changes: 11 additions & 3 deletions sys.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ local function exec_read(b, pattern, timeout)
return b:read(pattern, timeout)
end

if pattern == '*a' then
if pattern and pattern:sub(1, 1) == '*' then
pattern = pattern:sub(2)
end

if pattern == 'a' then
local data = {}
local chunk, err
while true do
Expand All @@ -57,8 +61,12 @@ local function exec_read(b, pattern, timeout)
return nil, err, concat(data)
end

if not pattern or pattern == '*l' then
return b:readline(timeout)
if not pattern then
pattern = 'l'
end

if pattern == 'l' or pattern == 'L' then
return b:readline(timeout, pattern == 'L')
end

error('invalid pattern:' .. tostring(pattern))
Expand Down

0 comments on commit 1bc6bc0

Please sign in to comment.