diff options
author | Kim Alvefur <zash@zash.se> | 2016-08-18 17:36:46 +0200 |
---|---|---|
committer | Kim Alvefur <zash@zash.se> | 2016-08-18 17:36:46 +0200 |
commit | 5ce8cd7c944d2e59621a79fb0fdc51a49f42af5e (patch) | |
tree | a89e877c6e83d9aa3b79825812361591bf12bf2e | |
parent | 2d2c10e83b62fbe72ac90043eca1c90d60a8cee5 (diff) | |
parent | 33a8994b3cf6aabe428b7cdf6bba7bdf68d9c366 (diff) | |
download | prosody-5ce8cd7c944d2e59621a79fb0fdc51a49f42af5e.tar.gz prosody-5ce8cd7c944d2e59621a79fb0fdc51a49f42af5e.zip |
Merge 0.10->trunk
-rw-r--r-- | net/http/codes.lua | 3 | ||||
-rw-r--r-- | net/http/parser.lua | 35 | ||||
-rw-r--r-- | net/http/server.lua | 13 | ||||
-rw-r--r-- | plugins/mod_http.lua | 3 | ||||
-rw-r--r-- | plugins/mod_register.lua | 2 | ||||
-rw-r--r-- | tools/ejabberdsql2prosody.lua | 52 |
6 files changed, 67 insertions, 41 deletions
diff --git a/net/http/codes.lua b/net/http/codes.lua index bc31c7dd..1090e545 100644 --- a/net/http/codes.lua +++ b/net/http/codes.lua @@ -55,6 +55,7 @@ local response_codes = { [428] = "Precondition Required"; [429] = "Too Many Requests"; [431] = "Request Header Fields Too Large"; + [451] = "Unavailable For Legal Reasons"; [500] = "Internal Server Error"; [501] = "Not Implemented"; @@ -70,4 +71,4 @@ local response_codes = { }; for k,v in pairs(response_codes) do response_codes[k] = k.." "..v; end -return setmetatable(response_codes, { __index = function(t, k) return k.." Unassigned"; end }) +return setmetatable(response_codes, { __index = function(_, k) return k.." Unassigned"; end }) diff --git a/net/http/parser.lua b/net/http/parser.lua index 6d7187da..fabbddad 100644 --- a/net/http/parser.lua +++ b/net/http/parser.lua @@ -1,5 +1,6 @@ local tonumber = tonumber; local assert = assert; +local t_insert, t_concat = table.insert, table.concat; local url_parse = require "socket.url".parse; local urldecode = require "util.http".urldecode; @@ -27,7 +28,9 @@ local httpstream = {}; function httpstream.new(success_cb, error_cb, parser_type, options_cb) local client = true; if not parser_type or parser_type == "server" then client = false; else assert(parser_type == "client", "Invalid parser type"); end - local buf = ""; + local buf, buflen, buftable = {}, 0, true; + local bodylimit = tonumber(options_cb and options_cb().body_size_limit) or 10*1024*1024; + local buflimit = tonumber(options_cb and options_cb().buffer_size_limit) or bodylimit * 2; local chunked, chunk_size, chunk_start; local state = nil; local packet; @@ -35,9 +38,10 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb) local have_body; local error; return { - feed = function(self, data) + feed = function(_, data) if error then return nil, "parse has failed"; end if not data then -- EOF + if buftable then buf, buftable = t_concat(buf), false; end if state and client and not len then -- reading client body until EOF packet.body = buf; success_cb(packet); @@ -46,9 +50,17 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb) end return; end - buf = buf..data; - while #buf > 0 do + if buftable then + t_insert(buf, data); + else + buf = { buf, data }; + buftable = true; + end + buflen = buflen + #data; + if buflen > buflimit then error = true; return error_cb("max-buffer-size-exceeded"); end + while buflen > 0 do if state == nil then -- read request + if buftable then buf, buftable = t_concat(buf), false; end local index = buf:find("\r\n\r\n", nil, true); if not index then return; end -- not enough data local method, path, httpversion, status_code, reason_phrase; @@ -79,6 +91,7 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb) if not first_line then error = true; return error_cb("invalid-status-line"); end chunked = have_body and headers["transfer-encoding"] == "chunked"; len = tonumber(headers["content-length"]); -- TODO check for invalid len + if len and len > bodylimit then error = true; return error_cb("content-length-limit-exceeded"); end if client then -- FIXME handle '100 Continue' response (by skipping it) if not have_body then len = 0; end @@ -115,11 +128,13 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb) }; end buf = buf:sub(index + 4); + buflen = #buf; state = true; end if state then -- read body if client then if chunked then + if buftable then buf, buftable = t_concat(buf), false; end if not buf:find("\r\n", nil, true) then return; end -- not enough data @@ -132,25 +147,29 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb) state, chunk_size = nil, nil; buf = buf:gsub("^.-\r\n\r\n", ""); -- This ensure extensions and trailers are stripped success_cb(packet); - elseif #buf - chunk_start - 2 >= chunk_size then -- we have a chunk + elseif buflen - chunk_start - 2 >= chunk_size then -- we have a chunk packet.body = packet.body..buf:sub(chunk_start, chunk_start + (chunk_size-1)); buf = buf:sub(chunk_start + chunk_size + 2); chunk_size, chunk_start = nil, nil; else -- Partial chunk remaining break; end - elseif len and #buf >= len then + elseif len and buflen >= len then + if buftable then buf, buftable = t_concat(buf), false; end if packet.code == 101 then - packet.body, buf = buf, ""; + packet.body, buf, buflen, buftable = buf, {}, 0, true; else packet.body, buf = buf:sub(1, len), buf:sub(len + 1); + buflen = #buf; end state = nil; success_cb(packet); else break; end - elseif #buf >= len then + elseif buflen >= len then + if buftable then buf, buftable = t_concat(buf), false; end packet.body, buf = buf:sub(1, len), buf:sub(len + 1); + buflen = #buf; state = nil; success_cb(packet); else break; diff --git a/net/http/server.lua b/net/http/server.lua index ba45ede0..8aa28f5c 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -22,6 +22,7 @@ local incomplete = {}; local listener = {}; local hosts = {}; local default_host; +local options = {}; local function is_wildcard_event(event) return event:sub(-2, -1) == "/*"; @@ -31,7 +32,7 @@ local function is_wildcard_match(wildcard_event, event) end local _handlers = events._handlers; -local recent_wildcard_events = cache.new(10000, function (key, value) +local recent_wildcard_events = cache.new(10000, function (key, value) -- luacheck: ignore 212/value rawset(_handlers, key, nil); end); @@ -133,7 +134,10 @@ function listener.onconnect(conn) sessions[conn] = nil; conn:close(); end - sessions[conn] = parser_new(success_cb, error_cb); + local function options_cb() + return options; + end + sessions[conn] = parser_new(success_cb, error_cb, "server", options_cb); end function listener.ondisconnect(conn) @@ -170,7 +174,7 @@ local headerfix = setmetatable({}, { end }); -function _M.hijack_response(response, listener) +function _M.hijack_response(response, listener) -- luacheck: ignore error("TODO"); end function handle_request(conn, request, finish_cb) @@ -350,6 +354,9 @@ end function _M.fire_event(event, ...) return events.fire_event(event, ...); end +function _M.set_option(name, value) + options[name] = value; +end _M.listener = listener; _M.codes = codes; diff --git a/plugins/mod_http.lua b/plugins/mod_http.lua index 81417cad..975663a5 100644 --- a/plugins/mod_http.lua +++ b/plugins/mod_http.lua @@ -18,6 +18,9 @@ local server = require "net.http.server"; server.set_default_host(module:get_option_string("http_default_host")); +server.set_option("body_size_limit", module:get_option_number("http_max_content_size")); +server.set_option("buffer_size_limit", module:get_option_number("http_max_buffer_size")); + local function normalize_path(path) if path:sub(-1,-1) == "/" then path = path:sub(1, -2); end if path:sub(1,1) ~= "/" then path = "/"..path; end diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index fda717f7..df833cad 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -226,7 +226,7 @@ module:hook("stanza/iq/jabber:iq:register:query", function(event) session.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not allowed to register an account.")); return true; elseif min_seconds_between_registrations and not whitelisted_ips[session.ip] then - if check_throttle(session.ip) then + if not check_throttle(session.ip) then session.send(st.error_reply(stanza, "wait", "not-acceptable")); return true; end diff --git a/tools/ejabberdsql2prosody.lua b/tools/ejabberdsql2prosody.lua index 69c8cfe8..d0ab71cf 100644 --- a/tools/ejabberdsql2prosody.lua +++ b/tools/ejabberdsql2prosody.lua @@ -42,10 +42,6 @@ local function read(expected) if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil").." on line "..line); end return ch; end -local function pushback(ch) - if last then error(); end - last = ch; -end local function peek() if not last then last = read(); end return last; @@ -176,9 +172,9 @@ return readFile(filename); ------ end -local arg, host = ...; +local arg, hostname = ...; local help = "/? -? ? /h -h /help -help --help"; -if not(arg and host) or help:find(arg, 1, true) then +if not(arg and hostname) or help:find(arg, 1, true) then print([[ejabberd SQL DB dump importer for Prosody Usage: ejabberdsql2prosody.lua filename.txt hostname @@ -201,8 +197,8 @@ local map = { --["vcard_search"] = {}; } local NULL = {}; -local t = parseFile(arg); -for name, data in pairs(t) do +local parsed = parseFile(arg); +for name, data in pairs(parsed) do local m = map[name]; if m then if #data > 0 and #data[1] ~= #m then @@ -219,10 +215,10 @@ for name, data in pairs(t) do end --print(serialize(t)); -for i, row in ipairs(t["users"] or NULL) do +for _, row in ipairs(parsed["users"] or NULL) do local node, password = row.username, row.password; - local ret, err = dm.store(node, host, "accounts", {password = password}); - print("["..(err or "success").."] accounts: "..node.."@"..host); + local ret, err = dm.store(node, hostname, "accounts", {password = password}); + print("["..(err or "success").."] accounts: "..node.."@"..hostname); end function roster(node, host, jid, item) @@ -258,7 +254,7 @@ function offline_msg(node, host, t, stanza) local ret, err = dm.list_append(node, host, "offline", st.preserialize(stanza)); print("["..(err or "success").."] offline: " ..node.."@"..host.." - "..os.date("!%Y-%m-%dT%H:%M:%SZ", t)); end -for i, row in ipairs(t["rosterusers"] or NULL) do +for _, row in ipairs(parsed["rosterusers"] or NULL) do local node, contact = row.username, row.jid; local name = row.nick; if name == "" then name = nil; end @@ -278,42 +274,42 @@ for i, row in ipairs(t["rosterusers"] or NULL) do elseif ask == "O" then ask = "subscribe"; elseif ask == "I" then - roster_pending(node, host, contact); + roster_pending(node, hostname, contact); ask = nil; elseif ask == "B" then - roster_pending(node, host, contact); + roster_pending(node, hostname, contact); ask = "subscribe"; else error("Unknown ask type: "..ask); end local item = {name = name, ask = ask, subscription = subscription, groups = {}}; - roster(node, host, contact, item); + roster(node, hostname, contact, item); end -for i, row in ipairs(t["rostergroups"] or NULL) do - roster_group(row.username, host, row.jid, row.grp); +for _, row in ipairs(parsed["rostergroups"] or NULL) do + roster_group(row.username, hostname, row.jid, row.grp); end -for i, row in ipairs(t["vcard"] or NULL) do +for _, row in ipairs(parsed["vcard"] or NULL) do local stanza, err = parse_xml(row.vcard); if stanza then - local ret, err = dm.store(row.username, host, "vcard", st.preserialize(stanza)); - print("["..(err or "success").."] vCard: "..row.username.."@"..host); + local ret, err = dm.store(row.username, hostname, "vcard", st.preserialize(stanza)); + print("["..(err or "success").."] vCard: "..row.username.."@"..hostname); else - print("[error] vCard XML parse failed: "..row.username.."@"..host); + print("[error] vCard XML parse failed: "..row.username.."@"..hostname); end end -for i, row in ipairs(t["private_storage"] or NULL) do +for _, row in ipairs(parsed["private_storage"] or NULL) do local stanza, err = parse_xml(row.data); if stanza then - private_storage(row.username, host, row.namespace, stanza); + private_storage(row.username, hostname, row.namespace, stanza); else - print("[error] Private XML parse failed: "..row.username.."@"..host); + print("[error] Private XML parse failed: "..row.username.."@"..hostname); end end -table.sort(t["spool"] or NULL, function(a,b) return a.seq < b.seq; end); -- sort by sequence number, just in case +table.sort(parsed["spool"] or NULL, function(a,b) return a.seq < b.seq; end); -- sort by sequence number, just in case local time_offset = os.difftime(os.time(os.date("!*t")), os.time(os.date("*t"))) -- to deal with timezones local date_parse = function(s) local year, month, day, hour, min, sec = s:match("(....)-?(..)-?(..)T(..):(..):(..)"); return os.time({year=year, month=month, day=day, hour=hour, min=min, sec=sec-time_offset}); end -for i, row in ipairs(t["spool"] or NULL) do +for _, row in ipairs(parsed["spool"] or NULL) do local stanza, err = parse_xml(row.xml); if stanza then local last_child = stanza.tags[#stanza.tags]; @@ -321,8 +317,8 @@ for i, row in ipairs(t["spool"] or NULL) do if last_child.name ~= "x" and last_child.attr.xmlns ~= "jabber:x:delay" then error("Last child of offline message is not a timestamp"); end stanza[#stanza], stanza.tags[#stanza.tags] = nil, nil; local t = date_parse(last_child.attr.stamp); - offline_msg(row.username, host, t, stanza); + offline_msg(row.username, hostname, t, stanza); else - print("[error] Offline message XML parsing failed: "..row.username.."@"..host); + print("[error] Offline message XML parsing failed: "..row.username.."@"..hostname); end end |