* 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("ltn12")
|
||||||
require("luci.util")
|
require("luci.util")
|
||||||
|
require("luci.http.protocol.filter")
|
||||||
|
|
||||||
HTTP_MAX_CONTENT = 1024*4 -- 4 kB maximum content size
|
HTTP_MAX_CONTENT = 1024*4 -- 4 kB maximum content size
|
||||||
HTTP_URLENC_MAXKEYLEN = 1024 -- maximum allowd size of urlencoded parameter names
|
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.type = "request"
|
||||||
msg.request_method = method:lower()
|
msg.request_method = method:lower()
|
||||||
msg.request_uri = uri
|
msg.request_uri = uri
|
||||||
msg.http_version = http_ver
|
msg.http_version = tonumber( http_ver )
|
||||||
msg.headers = { }
|
msg.headers = { }
|
||||||
|
|
||||||
-- We're done, next state is header parsing
|
-- We're done, next state is header parsing
|
||||||
|
@ -146,7 +147,7 @@ process_states['magic'] = function( msg, chunk )
|
||||||
msg.type = "response"
|
msg.type = "response"
|
||||||
msg.status_code = code
|
msg.status_code = code
|
||||||
msg.status_message = message
|
msg.status_message = message
|
||||||
msg.http_version = http_ver
|
msg.http_version = tonumber( http_ver )
|
||||||
msg.headers = { }
|
msg.headers = { }
|
||||||
|
|
||||||
-- We're done, next state is header parsing
|
-- We're done, next state is header parsing
|
||||||
|
@ -701,6 +702,18 @@ end
|
||||||
-- Parse a http message body
|
-- Parse a http message body
|
||||||
function parse_message_body( source, msg, filecb )
|
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 ?
|
-- Is it multipart/mime ?
|
||||||
if msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and
|
if msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and
|
||||||
msg.env.CONTENT_TYPE:match("^multipart/form%-data")
|
msg.env.CONTENT_TYPE:match("^multipart/form%-data")
|
||||||
|
@ -721,7 +734,6 @@ function parse_message_body( source, msg, filecb )
|
||||||
else
|
else
|
||||||
|
|
||||||
local sink
|
local sink
|
||||||
local length = 0
|
|
||||||
|
|
||||||
-- If we have a file callback then feed it
|
-- If we have a file callback then feed it
|
||||||
if type(filecb) == "function" then
|
if type(filecb) == "function" then
|
||||||
|
@ -733,7 +745,7 @@ function parse_message_body( source, msg, filecb )
|
||||||
msg.content_length = 0
|
msg.content_length = 0
|
||||||
|
|
||||||
sink = function( chunk )
|
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 = msg.content .. chunk
|
||||||
msg.content_length = msg.content_length + #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