module("luci.http.protocol", package.seeall)
-require("ltn12")
-require("luci.http.protocol.filter")
+local ltn12 = require("luci.ltn12")
HTTP_MAX_CONTENT = 1024*4 -- 4 kB maximum content size
HTTP_URLENC_MAXKEYLEN = 1024 -- maximum allowd size of urlencoded parameter names
+TSRC_BLOCKSIZE = 2048 -- target block size for throttling sources
-- Decode an urlencoded string.
-- Returns the decoded value.
-function urldecode( str )
+function urldecode( str, no_plus )
local function __chrdec( hex )
return string.char( tonumber( hex, 16 ) )
end
if type(str) == "string" then
- str = str:gsub( "+", " " ):gsub( "%%([a-fA-F0-9][a-fA-F0-9])", __chrdec )
+ if not no_plus then
+ str = str:gsub( "+", " " )
+ end
+
+ str = str:gsub( "%%([a-fA-F0-9][a-fA-F0-9])", __chrdec )
end
return str
if type(str) == "string" then
str = str:gsub(
- "([^a-zA-Z0-9$_%-%.+!*'(),])",
+ "([^a-zA-Z0-9$_%-%.%+!*'(),])",
__chrenc
)
end
end
+-- Parameter helper
+local function __initval( tbl, key )
+ if tbl[key] == nil then
+ tbl[key] = ""
+ elseif type(tbl[key]) == "string" then
+ tbl[key] = { tbl[key], "" }
+ else
+ table.insert( tbl[key], "" )
+ end
+end
+
+local function __appendval( tbl, key, chunk )
+ if type(tbl[key]) == "table" then
+ tbl[key][#tbl[key]] = tbl[key][#tbl[key]] .. chunk
+ else
+ tbl[key] = tbl[key] .. chunk
+ end
+end
+
+local function __finishval( tbl, key, handler )
+ if handler then
+ if type(tbl[key]) == "table" then
+ tbl[key][#tbl[key]] = handler( tbl[key][#tbl[key]] )
+ else
+ tbl[key] = handler( tbl[key] )
+ end
+ end
+end
+
+
-- Table of our process states
local process_states = { }
end
end
end
-
+
-- Can't handle it
return nil, "Invalid HTTP message magic"
end
-- Treat as form field
else
- msg.params[field] = ""
+ __initval( msg.params, field )
+
msg._mimecallback = function(chunk,eof)
- msg.params[field] = msg.params[field] .. chunk
+ __appendval( msg.params, field, chunk )
end
end
local key = urldecode( buffer:sub( 1, spos - 1 ) )
-- Prepare buffers
- msg.params[key] = ""
msg._urldeclength = msg._urldeclength + epos
msg._urldecbuffer = buffer:sub( epos + 1, #buffer )
filecb( field, chunk, eof )
end
else
+ __initval( msg.params, key )
+
msg._urldeccallback = function( chunk, eof )
- msg.params[key] = msg.params[key] .. chunk
+ __appendval( msg.params, key, chunk )
-- FIXME: Use a filter
if eof then
- msg.params[key] = urldecode( msg.params[key] )
+ __finishval( msg.params, key, urldecode )
end
end
end
local chunk, err, part = sock:receive("*l")
-- Line too long
- if chunk == nil then
+ if chunk == nil then
if err ~= "timeout" then
return nil, part
- and "Line exceeds maximum allowed length["..part.."]"
+ and "Line exceeds maximum allowed length"
or "Unexpected EOF"
else
return nil, err
-- XXX: we schould propably keep the maximum buffer size in sync with
-- the blocksize of our original source... but doesn't really matter
- if msg._mimebuffer ~= null and #msg._mimebuffer > 256 then
+ if msg._mimebuffer ~= nil and #msg._mimebuffer > TSRC_BLOCKSIZE then
return ""
else
return source()
-- Create a throttling LTN12 source
-- See explaination in mimedecode_message_body().
local tsrc = function()
- if msg._urldecbuffer ~= null and #msg._urldecbuffer > 0 then
+ if msg._urldecbuffer ~= nil and #msg._urldecbuffer > 0 then
return ""
else
return source()
-- Status codes
statusmsg = {
[200] = "OK",
+ [301] = "Moved Permanently",
+ [304] = "Not Modified",
[400] = "Bad Request",
[403] = "Forbidden",
[404] = "Not Found",
[405] = "Method Not Allowed",
[411] = "Length Required",
+ [412] = "Precondition Failed",
[500] = "Internal Server Error",
[503] = "Server Unavailable",
}