aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.luacheckrc20
-rw-r--r--net/dns.lua4
-rw-r--r--net/http/server.lua42
-rw-r--r--plugins/mod_http_errors.lua3
-rw-r--r--plugins/mod_http_files.lua26
-rwxr-xr-xprosodyctl2
-rw-r--r--tests/test.lua1
-rw-r--r--tests/test_net_http_parser.lua47
-rw-r--r--tests/test_util_cache.lua6
-rw-r--r--util/ip.lua8
-rw-r--r--util/openssl.lua2
11 files changed, 130 insertions, 31 deletions
diff --git a/.luacheckrc b/.luacheckrc
index 2fc05e75..90d2e273 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -8,16 +8,18 @@ codes = true
ignore = { "411/err", "421/err", "411/ok", "421/ok", "211/_ENV" }
files["plugins/"] = {
- ignore = { "122/module" };
+ globals = { "module" };
}
files["tests/"] = {
- ignore = {
- "113/assert_equal",
- "113/assert_table",
- "113/assert_function",
- "113/assert_string",
- "113/assert_boolean",
- "113/assert_is",
- "113/assert_is_not",
+ read_globals = {
+ "testlib_new_env",
+ "assert_equal",
+ "assert_table",
+ "assert_function",
+ "assert_string",
+ "assert_boolean",
+ "assert_is",
+ "assert_is_not",
+ "runtest",
};
}
diff --git a/net/dns.lua b/net/dns.lua
index 4a35fc1b..726b2b80 100644
--- a/net/dns.lua
+++ b/net/dns.lua
@@ -1011,7 +1011,7 @@ end
function resolver.print(response) -- - - - - - - - - - - - - resolver.print
- for s,s in pairs { 'id', 'qr', 'opcode', 'aa', 'tc', 'rd', 'ra', 'z',
+ for _, s in pairs { 'id', 'qr', 'opcode', 'aa', 'tc', 'rd', 'ra', 'z',
'rcode', 'qdcount', 'ancount', 'nscount', 'arcount' } do
print( string.format('%-30s', 'header.'..s), response.header[s], hint(response.header, s) );
end
@@ -1024,7 +1024,7 @@ function resolver.print(response) -- - - - - - - - - - - - - resolver.print
local common = { name=1, type=1, class=1, ttl=1, rdlength=1, rdata=1 };
local tmp;
- for s,s in pairs({'answer', 'authority', 'additional'}) do
+ for _, s in pairs({'answer', 'authority', 'additional'}) do
for i,rr in pairs(response[s]) do
for j,t in pairs({ 'name', 'type', 'class', 'ttl', 'rdlength' }) do
tmp = string.format('%s[%i].%s', s, i, t);
diff --git a/net/http/server.lua b/net/http/server.lua
index aeaa7416..bc39767f 100644
--- a/net/http/server.lua
+++ b/net/http/server.lua
@@ -13,10 +13,12 @@ local traceback = debug.traceback;
local tostring = tostring;
local cache = require "util.cache";
local codes = require "net.http.codes";
+local blocksize = require "socket".BLOCKSIZE or 2048;
local _M = {};
local sessions = {};
+local incomplete = {};
local listener = {};
local hosts = {};
local default_host;
@@ -140,17 +142,26 @@ function listener.ondisconnect(conn)
open_response.finished = true;
open_response:on_destroy();
end
+ incomplete[conn] = nil;
sessions[conn] = nil;
end
function listener.ondetach(conn)
sessions[conn] = nil;
+ incomplete[conn] = nil;
end
function listener.onincoming(conn, data)
sessions[conn]:feed(data);
end
+function listener.ondrain(conn)
+ local response = incomplete[conn];
+ if response and response._send_more then
+ response._send_more();
+ end
+end
+
local headerfix = setmetatable({}, {
__index = function(t, k)
local v = "\r\n"..k:gsub("_", "-"):gsub("%f[%w].", s_upper)..": ";
@@ -190,6 +201,7 @@ function handle_request(conn, request, finish_cb)
persistent = persistent;
conn = conn;
send = _M.send_response;
+ send_file = _M.send_file;
done = _M.finish_response;
finish_cb = finish_cb;
};
@@ -272,6 +284,36 @@ function _M.send_response(response, body)
response.conn:write(t_concat(output));
response:done();
end
+function _M.send_file(response, f)
+ if response.finished then return; end
+ local chunked = not response.headers.content_length;
+ if chunked then response.headers.transfer_encoding = "chunked"; end
+ incomplete[response.conn] = response;
+ response._send_more = function ()
+ if response.finished then
+ incomplete[response.conn] = nil;
+ return;
+ end
+ local chunk = f:read(blocksize);
+ if chunk then
+ if chunked then
+ chunk = ("%x\r\n%s\r\n"):format(#chunk, chunk);
+ end
+ -- io.write("."); io.flush();
+ response.conn:write(chunk);
+ else
+ if chunked then
+ response.conn:write("0\r\n\r\n");
+ end
+ -- io.write("\n");
+ if f.close then f:close(); end
+ incomplete[response.conn] = nil;
+ return response:done();
+ end
+ end
+ response.conn:write(t_concat(prepare_header(response)));
+ return true;
+end
function _M.finish_response(response)
if response.finished then return; end
response.finished = true;
diff --git a/plugins/mod_http_errors.lua b/plugins/mod_http_errors.lua
index 0c37e104..17d357e5 100644
--- a/plugins/mod_http_errors.lua
+++ b/plugins/mod_http_errors.lua
@@ -43,7 +43,8 @@ local html = [[
<p>$message</p>
<p>$extra</p>
</body>
-</html>]];
+</html>
+]];
html = html:gsub("%s%s+", "");
local entities = {
diff --git a/plugins/mod_http_files.lua b/plugins/mod_http_files.lua
index 3b602495..ab2f3966 100644
--- a/plugins/mod_http_files.lua
+++ b/plugins/mod_http_files.lua
@@ -17,6 +17,8 @@ local build_path = require"socket.url".build_path;
local path_sep = package.config:sub(1,1);
local base_path = module:get_option_string("http_files_dir", module:get_option_string("http_path"));
+local cache_size = module:get_option_number("http_files_cache_size", 128);
+local cache_max_file_size = module:get_option_number("http_files_cache_max_file_size", 4096);
local dir_indices = module:get_option("http_index_files", { "index.html", "index.htm" });
local directory_index = module:get_option_boolean("http_dir_listing");
@@ -81,7 +83,7 @@ function sanitize_path(path)
return "/"..table.concat(out, "/");
end
-local cache = setmetatable({}, { __mode = "kv" }); -- Let the garbage collector have it if it wants to.
+local cache = require "util.cache".new(cache_size);
function serve(opts)
if type(opts) ~= "table" then -- assume path string
@@ -109,7 +111,7 @@ function serve(opts)
local last_modified = os_date('!%a, %d %b %Y %H:%M:%S GMT', attr.modification);
response_headers.last_modified = last_modified;
- local etag = ("%02x-%x-%x-%x"):format(attr.dev or 0, attr.ino or 0, attr.size or 0, attr.modification or 0);
+ local etag = ('"%02x-%x-%x-%x"'):format(attr.dev or 0, attr.ino or 0, attr.size or 0, attr.modification or 0);
response_headers.etag = etag;
local if_none_match = request_headers.if_none_match
@@ -119,7 +121,7 @@ function serve(opts)
return 304;
end
- local data = cache[orig_path];
+ local data = cache:get(orig_path);
if data and data.etag == etag then
response_headers.content_type = data.content_type;
data = data.data;
@@ -147,18 +149,22 @@ function serve(opts)
else
local f, err = open(full_path, "rb");
- if f then
- data, err = f:read("*a");
- f:close();
- end
- if not data then
- module:log("debug", "Could not open or read %s. Error was %s", full_path, err);
+ if not f then
+ module:log("debug", "Could not open %s. Error was %s", full_path, err);
return 403;
end
local ext = full_path:match("%.([^./]+)$");
local content_type = ext and mime_map[ext];
- cache[orig_path] = { data = data; content_type = content_type; etag = etag };
response_headers.content_type = content_type;
+ if attr.size > cache_max_file_size then
+ response_headers.content_length = attr.size;
+ module:log("debug", "%d > cache_max_file_size", attr.size);
+ return response:send_file(f);
+ else
+ data = f:read("*a");
+ f:close();
+ end
+ cache:set(orig_path, { data = data; content_type = content_type; etag = etag });
end
return response:send(data);
diff --git a/prosodyctl b/prosodyctl
index 15d40f26..74681e7c 100755
--- a/prosodyctl
+++ b/prosodyctl
@@ -717,7 +717,7 @@ function cert_commands.config(arg)
else
show_message("Please provide details to include in the certificate config file.");
show_message("Leave the field empty to use the default value or '.' to exclude the field.")
- for i, k in ipairs(openssl._DN_order) do
+ for _, k in ipairs(openssl._DN_order) do
local v = conf.distinguished_name[k];
if v then
local nv;
diff --git a/tests/test.lua b/tests/test.lua
index bb15250d..d6aa3b31 100644
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -28,6 +28,7 @@ function run_all_tests()
dotest "util.random"
dotest "util.xml"
dotest "util.xmppstream"
+ dotest "net.http.parser"
dosingletest("test_sasl.lua", "latin1toutf8");
dosingletest("test_utf8.lua", "valid");
diff --git a/tests/test_net_http_parser.lua b/tests/test_net_http_parser.lua
new file mode 100644
index 00000000..1157b5ac
--- /dev/null
+++ b/tests/test_net_http_parser.lua
@@ -0,0 +1,47 @@
+local httpstreams = { [[
+GET / HTTP/1.1
+Host: example.com
+
+]], [[
+HTTP/1.1 200 OK
+Content-Length: 0
+
+]], [[
+HTTP/1.1 200 OK
+Content-Length: 7
+
+Hello
+HTTP/1.1 200 OK
+Transfer-Encoding: chunked
+
+1
+H
+1
+e
+2
+ll
+1
+o
+0
+
+
+]]
+}
+
+function new(new)
+
+ for _, stream in ipairs(httpstreams) do
+ local success;
+ local function success_cb(packet)
+ success = true;
+ end
+ stream = stream:gsub("\n", "\r\n");
+ local parser = new(success_cb, error, stream:sub(1,4) == "HTTP" and "client" or "server")
+ for chunk in stream:gmatch("..?.?") do
+ parser:feed(chunk);
+ end
+
+ assert_is(success);
+ end
+
+end
diff --git a/tests/test_util_cache.lua b/tests/test_util_cache.lua
index 78666edc..cbc60bc7 100644
--- a/tests/test_util_cache.lua
+++ b/tests/test_util_cache.lua
@@ -196,12 +196,12 @@ function new(new)
assert_equal(i, 4);
local evicted_key, evicted_value;
- local c = new(3, function (_key, _value)
+ local c2 = new(3, function (_key, _value)
evicted_key, evicted_value = _key, _value;
end);
local function set(k, v, should_evict_key, should_evict_value)
evicted_key, evicted_value = nil, nil;
- c:set(k, v);
+ c2:set(k, v);
assert_equal(evicted_key, should_evict_key);
assert_equal(evicted_value, should_evict_value);
end
@@ -219,7 +219,7 @@ function new(new)
local evicted_key, evicted_value;
- local c3 = new(1, function (_key, _value, c3)
+ local c3 = new(1, function (_key, _value)
evicted_key, evicted_value = _key, _value;
if _key == "a" then
-- Sanity check for what we're evicting
diff --git a/util/ip.lua b/util/ip.lua
index ec3b4d7e..81a98ef7 100644
--- a/util/ip.lua
+++ b/util/ip.lua
@@ -51,15 +51,15 @@ local function toBits(ip)
if not ip:match(":$") then fields[#fields] = nil; end
for i, field in ipairs(fields) do
if field:len() == 0 and i ~= 1 and i ~= #fields then
- for i = 1, 16 * (9 - #fields) do
+ for _ = 1, 16 * (9 - #fields) do
result = result .. "0";
end
else
- for i = 1, 4 - field:len() do
+ for _ = 1, 4 - field:len() do
result = result .. "0000";
end
- for i = 1, field:len() do
- result = result .. hex2bits[field:sub(i,i)];
+ for j = 1, field:len() do
+ result = result .. hex2bits[field:sub(j, j)];
end
end
end
diff --git a/util/openssl.lua b/util/openssl.lua
index 33234a7d..abd90a84 100644
--- a/util/openssl.lua
+++ b/util/openssl.lua
@@ -70,7 +70,7 @@ function ssl_config:serialize()
end
end
elseif k == "distinguished_name" then
- for i, k in ipairs(t[1] and t or DN_order) do
+ for _, k in ipairs(t[1] and t or DN_order) do
local v = t[k];
if v then
s = s .. ("%s = %s\n"):format(k, v);