Changeset

7489:d32406f27efd

net.http.server: Add response method for reading response body from a file handle
author Kim Alvefur <zash@zash.se>
date Mon, 11 Jul 2016 11:52:43 +0200
parents 7487:88a0a947e58c
children 7490:b75b08af7a78
files net/http/server.lua
diffstat 1 files changed, 42 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/net/http/server.lua	Sat Jul 09 21:55:37 2016 +0800
+++ b/net/http/server.lua	Mon Jul 11 11:52:43 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;