Merge 0.10->trunk
authorKim Alvefur <zash@zash.se>
Wed, 13 Jul 2016 10:25:52 +0200
changeset 7497 f82356adcd71
parent 7491 cdabf8199903 (current diff)
parent 7496 f67b7509ee28 (diff)
child 7500 22942eda53f8
Merge 0.10->trunk
prosodyctl
tests/test.lua
--- a/.luacheckrc	Sat Jul 09 22:33:04 2016 +0200
+++ b/.luacheckrc	Wed Jul 13 10:25:52 2016 +0200
@@ -8,16 +8,18 @@
 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",
 	};
 }
--- a/net/dns.lua	Sat Jul 09 22:33:04 2016 +0200
+++ b/net/dns.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -1011,7 +1011,7 @@
 
 
 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 @@
 
 	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);
--- a/net/http/server.lua	Sat Jul 09 22:33:04 2016 +0200
+++ b/net/http/server.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -13,10 +13,12 @@
 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 @@
 		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 @@
 		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 @@
 	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;
--- a/plugins/mod_http_errors.lua	Sat Jul 09 22:33:04 2016 +0200
+++ b/plugins/mod_http_errors.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -43,7 +43,8 @@
         <p>$message</p>
         <p>$extra</p>
 </body>
-</html>]];
+</html>
+]];
 html = html:gsub("%s%s+", "");
 
 local entities = {
--- a/plugins/mod_http_files.lua	Sat Jul 09 22:33:04 2016 +0200
+++ b/plugins/mod_http_files.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -17,6 +17,8 @@
 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 @@
 	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 @@
 		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 @@
 			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 @@
 
 		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);
--- a/prosodyctl	Sat Jul 09 22:33:04 2016 +0200
+++ b/prosodyctl	Wed Jul 13 10:25:52 2016 +0200
@@ -717,7 +717,7 @@
 		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;
--- a/tests/test.lua	Sat Jul 09 22:33:04 2016 +0200
+++ b/tests/test.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -28,6 +28,7 @@
 	dotest "util.random"
 	dotest "util.xml"
 	dotest "util.xmppstream"
+	dotest "net.http.parser"
 
 	dosingletest("test_sasl.lua", "latin1toutf8");
 	dosingletest("test_utf8.lua", "valid");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_net_http_parser.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -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
--- a/tests/test_util_cache.lua	Sat Jul 09 22:33:04 2016 +0200
+++ b/tests/test_util_cache.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -196,12 +196,12 @@
 	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 @@
 	
 
 	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
--- a/util/ip.lua	Sat Jul 09 22:33:04 2016 +0200
+++ b/util/ip.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -51,15 +51,15 @@
 	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
--- a/util/openssl.lua	Sat Jul 09 22:33:04 2016 +0200
+++ b/util/openssl.lua	Wed Jul 13 10:25:52 2016 +0200
@@ -70,7 +70,7 @@
 				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);