summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2008-06-22 12:07:37 +0000
committerJo-Philipp Wich <jow@openwrt.org>2008-06-22 12:07:37 +0000
commita038da390d7fd3a75b5a1045afbb4d9782556c57 (patch)
tree1051de9fff9496a21c823aa789645939427a7376
parent90aef16aea255b6f863cda36f118bf5bde0316b4 (diff)
* luci/libs: add support for chunked transfer decoding in http.protocol
-rw-r--r--libs/http/luasrc/http/protocol.lua24
-rw-r--r--libs/http/luasrc/http/protocol/filter.lua81
2 files changed, 99 insertions, 6 deletions
diff --git a/libs/http/luasrc/http/protocol.lua b/libs/http/luasrc/http/protocol.lua
index 6e53d7ca1..08e8ba256 100644
--- a/libs/http/luasrc/http/protocol.lua
+++ b/libs/http/luasrc/http/protocol.lua
@@ -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
@@ -435,7 +436,7 @@ process_states['urldecode-key'] = function( msg, chunk, filecb )
else
msg._urldeccallback = function( chunk, eof )
msg.params[key] = msg.params[key] .. chunk
-
+
-- FIXME: Use a filter
if eof then
msg.params[key] = urldecode( msg.params[key] )
@@ -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")
@@ -713,7 +726,7 @@ function parse_message_body( source, msg, filecb )
msg.env.CONTENT_TYPE == "application/x-www-form-urlencoded"
then
return urldecode_message_body( source, msg, filecb )
-
+
-- Unhandled encoding
-- If a file callback is given then feed it line by line, else
@@ -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
diff --git a/libs/http/luasrc/http/protocol/filter.lua b/libs/http/luasrc/http/protocol/filter.lua
new file mode 100644
index 000000000..71263c351
--- /dev/null
+++ b/libs/http/luasrc/http/protocol/filter.lua
@@ -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