Merge 0.10->trunk
authorKim Alvefur <zash@zash.se>
Wed, 13 Jul 2016 08:25:52 +0000 (10:25 +0200)
committerKim Alvefur <zash@zash.se>
Wed, 13 Jul 2016 08:25:52 +0000 (10:25 +0200)
.luacheckrc
net/dns.lua
net/http/server.lua
plugins/mod_http_errors.lua
plugins/mod_http_files.lua
prosodyctl
tests/test.lua
tests/test_net_http_parser.lua [new file with mode: 0644]
tests/test_util_cache.lua
util/ip.lua
util/openssl.lua

index 2fc05e7527ef1643f106d315b7a3ffc13e2d3275..90d2e27398107aaf630f5c607ba262a815f8ebc2 100644 (file)
@@ -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",
        };
 }
index 4a35fc1be79640660c374d1239910ec8bb253f08..726b2b80db4ec324496862993f9acc82c79077ca 100644 (file)
@@ -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);
index aeaa7416065f1bf646d5c13b6ce9d511b2317d84..bc39767fe49562e1d95c9c873902a27efb67f03a 100644 (file)
@@ -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;
index 0c37e1044eed1ea5b3df81491ac7e1cbcc2e041f..17d357e546ac7cd9055b68417fb0ea8583a0c478 100644 (file)
@@ -43,7 +43,8 @@ local html = [[
         <p>$message</p>
         <p>$extra</p>
 </body>
-</html>]];
+</html>
+]];
 html = html:gsub("%s%s+", "");
 
 local entities = {
index 3b60249559c6e7e42bee94699d0f14ba122f7c4b..ab2f3966f859a3745ae517d415c18d4390189713 100644 (file)
@@ -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);
index 15d40f26a7b66e16bb88010b6587be5d6f8b01a9..74681e7cd9c66863c31fff1c71371cd4323b025b 100755 (executable)
@@ -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;
index bb15250d0a5f1a0d667b51bf2fc614af1cb36182..d6aa3b31937cca3de906fc75c03bc003590c2fc6 100644 (file)
@@ -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 (file)
index 0000000..1157b5a
--- /dev/null
@@ -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
index 78666edc44e02018fb454005dfe9481aa1e08f4e..cbc60bc7da7416d9f8945662acd5c2017ef0f096 100644 (file)
@@ -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
index ec3b4d7e56ba4c8342d11e5af00a044d25fe418e..81a98ef7dcec640c429c356baa0f8f845fba0a5e 100644 (file)
@@ -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
index 33234a7d9feaf45184279deb39080714ea6752a8..abd90a849a79c46e37f313e357a8b37fde811bb0 100644 (file)
@@ -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);