* luci/libs: improved linereader implementation

This commit is contained in:
Jo-Philipp Wich 2008-06-15 20:08:29 +00:00
parent 6fa9ec035b
commit 72aa111b22

View file

@ -21,7 +21,7 @@ require("luci.util")
HTTP_MAX_CONTENT = 1048576 -- 1 MB HTTP_MAX_CONTENT = 1048576 -- 1 MB
HTTP_DEFAULT_CTYPE = "text/html" -- default content type HTTP_DEFAULT_CTYPE = "text/html" -- default content type
HTTP_DEFAULT_VERSION = "1.0" -- HTTP default version HTTP_DEFAULT_VERSION = "1.0" -- HTTP default version
HTTP_DEFAULT_LINEBUF = 1024 * 4 -- Read buffer size
-- Decode an urlencoded string. -- Decode an urlencoded string.
-- Returns the decoded value. -- Returns the decoded value.
@ -116,7 +116,7 @@ function mimedecode( data, boundary, filecb )
local params = { } local params = { }
-- create a line reader -- create a line reader
local reader = _linereader( data ) local reader = _linereader( data, HTTP_DEFAULT_LINEBUF )
-- state variables -- state variables
local in_part = false local in_part = false
@ -129,9 +129,8 @@ function mimedecode( data, boundary, filecb )
local field local field
local clen = 0 local clen = 0
-- try to read all mime parts -- try to read all mime parts
for line in reader do for line, eol in reader do
-- update content length -- update content length
clen = clen + line:len() clen = clen + line:len()
@ -327,7 +326,7 @@ end
-- Parse a http message -- Parse a http message
function parse_message( data, filecb ) function parse_message( data, filecb )
local reader = _linereader( data ) local reader = _linereader( data, HTTP_DEFAULT_LINEBUF )
local message = parse_message_header( reader ) local message = parse_message_header( reader )
if message then if message then
@ -342,7 +341,7 @@ end
function parse_message_header( data ) function parse_message_header( data )
-- Create a line reader -- Create a line reader
local reader = _linereader( data ) local reader = _linereader( data, HTTP_DEFAULT_LINEBUF )
local message = { } local message = { }
-- Try to extract magic -- Try to extract magic
@ -487,42 +486,72 @@ function parse_message_body( reader, message, filecb )
end end
function _linereader( obj ) function _linereader( obj, bufsz )
bufsz = ( bufsz and bufsz >= 256 ) and bufsz or 256
local __read = function() return nil end
local __eof = function(x) return type(x) ~= "string" or #x == 0 end
local _pos = 1
local _buf = ""
local _eof = nil
-- object is string -- object is string
if type(obj) == "string" then if type(obj) == "string" then
return obj:gmatch( "[^\r\n]*\r?\n" ) __read = function() return obj:sub( _pos, _pos + bufsz - #_buf - 1 ) end
-- object implements a receive() or read() function
elseif type(obj) == "userdata" and ( type(obj.receive) == "function" or type(obj.read) == "function" ) then
if type(obj.read) == "function" then
__read = function() return obj:read( bufsz ) end
else
__read = function() return obj:receive( bufsz ) end
end
-- object is a function -- object is a function
elseif type(obj) == "function" then elseif type(obj) == "function" then
return obj return obj
-- object is a table and implements a readline() function
elseif type(obj) == "table" and type(obj.readline) == "function" then
return obj.readline
-- object is a table and has a lines property
elseif type(obj) == "table" and obj.lines then
-- decide wheather to use "lines" as function or table
local _lns = ( type(obj.lines) == "function" ) and obj.lines() or obj.lines
local _pos = 1
return function()
if _pos <= #_lns then
_pos = _pos + 1
return _lns[_pos]
end
end
-- no usable data type -- no usable data type
else else
-- dummy iterator -- dummy iterator
return __read
end
-- generic block to line algorithm
return function() return function()
if not _eof then
local buffer = __read()
if __eof( buffer ) then
buffer = ""
end
_pos = _pos + #buffer
buffer = _buf .. buffer
local crlf, endpos = buffer:find("\r?\n")
if crlf then
_buf = buffer:sub( endpos + 1, #buffer )
return buffer:sub( 1, endpos ), true
else
-- check for eof
_eof = __eof( buffer )
-- clear overflow buffer
_buf = ""
return buffer, false
end
else
return nil return nil
end end
end end