* luci/libs: add support for chunked transfer decoding in http.protocol
This commit is contained in:
parent
90aef16aea
commit
a038da390d
2 changed files with 99 additions and 6 deletions
|
@ -17,6 +17,7 @@ module("luci.http.protocol", package.seeall)
|
|||
|
||||
require("ltn12")
|
||||
require("luci.util")
|
||||
require("luci.http.protocol.filter")
|
||||
|
||||
HTTP_MAX_CONTENT = 1024*4 -- 4 kB maximum content size
|
||||
HTTP_URLENC_MAXKEYLEN = 1024 -- maximum allowd size of urlencoded parameter names
|
||||
|
@ -127,7 +128,7 @@ process_states['magic'] = function( msg, chunk )
|
|||
msg.type = "request"
|
||||
msg.request_method = method:lower()
|
||||
msg.request_uri = uri
|
||||
msg.http_version = http_ver
|
||||
msg.http_version = tonumber( http_ver )
|
||||
msg.headers = { }
|
||||
|
||||
-- We're done, next state is header parsing
|
||||
|
@ -146,7 +147,7 @@ process_states['magic'] = function( msg, chunk )
|
|||
msg.type = "response"
|
||||
msg.status_code = code
|
||||
msg.status_message = message
|
||||
msg.http_version = http_ver
|
||||
msg.http_version = tonumber( http_ver )
|
||||
msg.headers = { }
|
||||
|
||||
-- We're done, next state is header parsing
|
||||
|
@ -701,6 +702,18 @@ end
|
|||
-- Parse a http message body
|
||||
function parse_message_body( source, msg, filecb )
|
||||
|
||||
-- Install an additional filter if we're operating on chunked transfer
|
||||
-- coding and client is HTTP/1.1 capable
|
||||
if msg.http_version == 1.1 and
|
||||
msg.headers['Transfer-Encoding'] and
|
||||
msg.headers['Transfer-Encoding']:find("chunked")
|
||||
then
|
||||
source = ltn12.source.chain(
|
||||
source, luci.http.protocol.filter.decode_chunked
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
-- Is it multipart/mime ?
|
||||
if msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and
|
||||
msg.env.CONTENT_TYPE:match("^multipart/form%-data")
|
||||
|
@ -721,7 +734,6 @@ function parse_message_body( source, msg, filecb )
|
|||
else
|
||||
|
||||
local sink
|
||||
local length = 0
|
||||
|
||||
-- If we have a file callback then feed it
|
||||
if type(filecb) == "function" then
|
||||
|
@ -733,7 +745,7 @@ function parse_message_body( source, msg, filecb )
|
|||
msg.content_length = 0
|
||||
|
||||
sink = function( chunk )
|
||||
if ( msg.content_length ) + #chunk <= HTTP_MAX_CONTENT then
|
||||
if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then
|
||||
|
||||
msg.content = msg.content .. chunk
|
||||
msg.content_length = msg.content_length + #chunk
|
||||
|
|
81
libs/http/luasrc/http/protocol/filter.lua
Normal file
81
libs/http/luasrc/http/protocol/filter.lua
Normal file
|
@ -0,0 +1,81 @@
|
|||
--[[
|
||||
|
||||
HTTP protocol implementation for LuCI - filter implementation
|
||||
(c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
$Id$
|
||||
|
||||
]]--
|
||||
|
||||
module("luci.http.protocol.filter", package.seeall)
|
||||
|
||||
require("ltn12")
|
||||
|
||||
|
||||
-- Factory that produces a filter which normalizes chunked transfer encoding
|
||||
function decode_chunked()
|
||||
|
||||
local length = 0
|
||||
local read = 0
|
||||
|
||||
return ltn12.filter.cycle(
|
||||
function( chunk, ctx )
|
||||
|
||||
if chunk ~= nil then
|
||||
|
||||
-- EOF
|
||||
if ctx == nil then
|
||||
if ( length - read ) > 0 then
|
||||
return nil, "Unexpected EOF"
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
chunk = ctx .. chunk
|
||||
|
||||
local buf = ""
|
||||
while true do
|
||||
|
||||
if read == length then
|
||||
|
||||
-- Find chunk length indicator
|
||||
local spos, epos = chunk:find("^\r?\n?[a-fA-F0-9]+ *\r\n")
|
||||
if spos and spos == 1 then
|
||||
read = 0
|
||||
length = tonumber(
|
||||
chunk:sub( 1, epos ):gsub( "[^a-fA-F0-9]", "" ), 16
|
||||
)
|
||||
|
||||
-- Check for end of chunk
|
||||
if length > 0 then
|
||||
chunk = chunk:sub( epos + 1, #chunk )
|
||||
else
|
||||
return buf, ""
|
||||
end
|
||||
else
|
||||
return "", nil
|
||||
end
|
||||
else
|
||||
if ( read + #chunk ) <= length then
|
||||
read = read + #chunk
|
||||
return buf .. chunk, ""
|
||||
else
|
||||
local rest = length - read
|
||||
read = read + rest
|
||||
buf = buf .. chunk:sub( 1, rest )
|
||||
chunk = chunk:sub( rest + 1, #chunk )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
""
|
||||
)
|
||||
end
|
Loading…
Reference in a new issue