* luci/libs: add support for chunked transfer decoding in http.protocol

This commit is contained in:
Jo-Philipp Wich 2008-06-22 12:07:37 +00:00
parent 90aef16aea
commit a038da390d
2 changed files with 99 additions and 6 deletions

View file

@ -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

View 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