From 9be7bd1055aabdbbc663005ad11bc4b9cc1215f2 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Sat, 22 Oct 2011 18:29:23 +0200 Subject: s2smanager, xmppserver_listener: Support for connecting to other servers via IPv6 --- net/xmppserver_listener.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua index 3af0b962..fe661033 100644 --- a/net/xmppserver_listener.lua +++ b/net/xmppserver_listener.lua @@ -178,7 +178,7 @@ end function xmppserver.ondisconnect(conn, err) local session = sessions[conn]; if session then - if err and err ~= "closed" and session.srv_hosts then + if err and err ~= "closed" then (session.log or log)("debug", "s2s connection attempt failed: %s", err); if s2s_attempt_connect(session, err) then (session.log or log)("debug", "...so we're going to try another target"); -- cgit v1.2.3 From a71b4036179108e3de89a8859f1e2d90f4407451 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 26 Oct 2011 02:03:33 +0200 Subject: s2smanager, net.dns: Fix handling for NXNAME and SRV target of "." --- net/dns.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/dns.lua b/net/dns.lua index 8f428476..5b32a56c 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -358,6 +358,7 @@ function resolver:name() -- - - - - - - - - - - - - - - - - - - - - - name local remember, pointers = nil, 0; local len = self:byte(); local n = {}; + if len == 0 then return "." end -- Root label while len > 0 do if len >= 0xc0 then -- name is "compressed" pointers = pointers + 1; -- cgit v1.2.3 From 6975f1a07decc49411d37d7f7ab82d92f0104634 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 28 Nov 2011 03:04:50 +0000 Subject: net.server_select: Autostart SSL negotiation as the last part of socket setup to avoid a traceback (#262) (thanks Maranda) --- net/server_select.lua | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index 412d03c0..8802f620 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -596,25 +596,23 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport handler.sendbuffer = handshake handshake( socket ) -- do handshake end - handler.readbuffer = _readbuffer - handler.sendbuffer = _sendbuffer - - if sslctx then - out_put "server.lua: auto-starting ssl negotiation..." - handler.autostart_ssl = true; - handler:starttls(sslctx); - end - - else - handler.readbuffer = _readbuffer - handler.sendbuffer = _sendbuffer end + + handler.readbuffer = _readbuffer + handler.sendbuffer = _sendbuffer send = socket.send receive = socket.receive shutdown = ( ssl and id ) or socket.shutdown _socketlist[ socket ] = handler _readlistlen = addsocket(_readlist, socket, _readlistlen) + + if sslctx and luasec then + out_put "server.lua: auto-starting ssl negotiation..." + handler.autostart_ssl = true; + handler:starttls(sslctx); + end + return handler, socket end -- cgit v1.2.3 From 11a9469d1d494d42f02c965008788d67ce8677f8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 28 Nov 2011 14:27:52 +0000 Subject: net.xmppserver_listener: Set default interface to '*' (fixes traceback) (thanks Zash) --- net/xmppserver_listener.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua index fe661033..a92b1a7f 100644 --- a/net/xmppserver_listener.lua +++ b/net/xmppserver_listener.lua @@ -66,7 +66,7 @@ function stream_callbacks.handlestanza(session, stanza) end local sessions = {}; -local xmppserver = { default_port = 5269, default_mode = "*a" }; +local xmppserver = { default_port = 5269, default_mode = "*a", default_interface = "*" }; -- These are session methods -- -- cgit v1.2.3 From a67ef03130426331ed9698c7f327ccc12b2d2e78 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 9 Dec 2011 11:38:35 +0500 Subject: net.httpserver: Removed unused import. --- net/httpserver.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/httpserver.lua b/net/httpserver.lua index 74f61c56..44e8e24d 100644 --- a/net/httpserver.lua +++ b/net/httpserver.lua @@ -7,7 +7,6 @@ -- -local server = require "net.server" local url_parse = require "socket.url".parse; local httpstream_new = require "util.httpstream".new; -- cgit v1.2.3 From 876ae42f2a1613291a6ac9ccba8ab0ec5c145220 Mon Sep 17 00:00:00 2001 From: Marco Cirillo Date: Fri, 6 Jan 2012 21:43:30 +0000 Subject: net.xmppcomponent_listener: removed unused variable reference. --- net/xmppcomponent_listener.lua | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/xmppcomponent_listener.lua b/net/xmppcomponent_listener.lua index 90293559..dd7b2b91 100644 --- a/net/xmppcomponent_listener.lua +++ b/net/xmppcomponent_listener.lua @@ -7,8 +7,6 @@ -- -local hosts = _G.hosts; - local t_concat = table.concat; local tostring = tostring; local type = type; -- cgit v1.2.3 From 5d81665f61754324c10879d5ef7bf259c4e3debf Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 16 Jan 2012 04:44:23 +0000 Subject: net.server_event: Fix :pause() to actually stop reading from the socket, rather than ignoring socket-readable events (!), and :resume() to restart the event listener --- net/server_event.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_event.lua b/net/server_event.lua index f4745c34..dbf5161f 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -295,7 +295,10 @@ do end function interface_mt:resume() - return self:_lock(self.nointerface, false, self.nowriting); + self:_lock(self.nointerface, false, self.nowriting); + if not self.eventread then + self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ); -- register callback + end end function interface_mt:counter(c) @@ -642,6 +645,10 @@ do return -1 end end + if interface.noreading then + interface.eventread = nil; + return -1; + end return EV_READ, cfg.READ_TIMEOUT end end -- cgit v1.2.3 From 0a3dc54d63e4f6b263831815025c09c1eb73d093 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 17 Jan 2012 17:56:36 +0000 Subject: xmppserver_listener: Only re-attempt connection on disconnect if it was an unauthenticated s2sout (thanks Medics for the log) --- net/xmppserver_listener.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua index a92b1a7f..048c6c7d 100644 --- a/net/xmppserver_listener.lua +++ b/net/xmppserver_listener.lua @@ -178,7 +178,7 @@ end function xmppserver.ondisconnect(conn, err) local session = sessions[conn]; if session then - if err and err ~= "closed" then + if err and err ~= "closed" and session.type == "s2sout_unauthed" then (session.log or log)("debug", "s2s connection attempt failed: %s", err); if s2s_attempt_connect(session, err) then (session.log or log)("debug", "...so we're going to try another target"); -- cgit v1.2.3 From 13b36f8ded00794f3142887c41ac8b31efb01e4b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sun, 22 Jan 2012 23:57:13 +0000 Subject: mod_c2s, sessionmanager, xmppclient_listener: Move all c2s network and stream logic into a new module, mod_c2s --- net/xmppclient_listener.lua | 179 -------------------------------------------- 1 file changed, 179 deletions(-) delete mode 100644 net/xmppclient_listener.lua (limited to 'net') diff --git a/net/xmppclient_listener.lua b/net/xmppclient_listener.lua deleted file mode 100644 index 4cc90cbf..00000000 --- a/net/xmppclient_listener.lua +++ /dev/null @@ -1,179 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - - - -local logger = require "logger"; -local log = logger.init("xmppclient_listener"); -local new_xmpp_stream = require "util.xmppstream".new; - -local connlisteners_register = require "net.connlisteners".register; - -local sessionmanager = require "core.sessionmanager"; -local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session; -local sm_streamopened = sessionmanager.streamopened; -local sm_streamclosed = sessionmanager.streamclosed; -local st = require "util.stanza"; -local xpcall = xpcall; -local tostring = tostring; -local type = type; -local traceback = debug.traceback; - -local config = require "core.configmanager"; -local opt_keepalives = config.get("*", "core", "tcp_keepalives"); - -local stream_callbacks = { default_ns = "jabber:client", - streamopened = sm_streamopened, streamclosed = sm_streamclosed, handlestanza = core_process_stanza }; - -local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; - -function stream_callbacks.error(session, error, data) - if error == "no-stream" then - session.log("debug", "Invalid opening stream header"); - session:close("invalid-namespace"); - elseif error == "parse-error" then - (session.log or log)("debug", "Client XML parse error: %s", tostring(data)); - session:close("not-well-formed"); - elseif error == "stream-error" then - local condition, text = "undefined-condition"; - for child in data:children() do - if child.attr.xmlns == xmlns_xmpp_streams then - if child.name ~= "text" then - condition = child.name; - else - text = child:get_text(); - end - if condition ~= "undefined-condition" and text then - break; - end - end - end - text = condition .. (text and (" ("..text..")") or ""); - session.log("info", "Session closed by remote with error: %s", text); - session:close(nil, text); - end -end - -local function handleerr(err) log("error", "Traceback[c2s]: %s: %s", tostring(err), traceback()); end -function stream_callbacks.handlestanza(session, stanza) - stanza = session.filter("stanzas/in", stanza); - if stanza then - return xpcall(function () return core_process_stanza(session, stanza) end, handleerr); - end -end - -local sessions = {}; -local xmppclient = { default_port = 5222, default_mode = "*a" }; - --- These are session methods -- - -local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; -local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" }; -local function session_close(session, reason) - local log = session.log or log; - if session.conn then - if session.notopen then - session.send(""); - session.send(st.stanza("stream:stream", default_stream_attr):top_tag()); - end - if reason then - if type(reason) == "string" then -- assume stream error - log("info", "Disconnecting client, is: %s", reason); - session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); - elseif type(reason) == "table" then - if reason.condition then - local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up(); - if reason.text then - stanza:tag("text", stream_xmlns_attr):text(reason.text):up(); - end - if reason.extra then - stanza:add_child(reason.extra); - end - log("info", "Disconnecting client, is: %s", tostring(stanza)); - session.send(stanza); - elseif reason.name then -- a stanza - log("info", "Disconnecting client, is: %s", tostring(reason)); - session.send(reason); - end - end - end - session.send(""); - session.conn:close(); - xmppclient.ondisconnect(session.conn, (reason and (reason.text or reason.condition)) or reason or "session closed"); - end -end - - --- End of session methods -- - -function xmppclient.onconnect(conn) - local session = sm_new_session(conn); - sessions[conn] = session; - - session.log("info", "Client connected"); - - -- Client is using legacy SSL (otherwise mod_tls sets this flag) - if conn:ssl() then - session.secure = true; - end - - if opt_keepalives ~= nil then - conn:setoption("keepalive", opt_keepalives); - end - - session.close = session_close; - - local stream = new_xmpp_stream(session, stream_callbacks); - session.stream = stream; - - session.notopen = true; - - function session.reset_stream() - session.notopen = true; - session.stream:reset(); - end - - local filter = session.filter; - function session.data(data) - data = filter("bytes/in", data); - if data then - local ok, err = stream:feed(data); - if ok then return; end - log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); - session:close("not-well-formed"); - end - end - - local handlestanza = stream_callbacks.handlestanza; - function session.dispatch_stanza(session, stanza) - return handlestanza(session, stanza); - end -end - -function xmppclient.onincoming(conn, data) - local session = sessions[conn]; - if session then - session.data(data); - end -end - -function xmppclient.ondisconnect(conn, err) - local session = sessions[conn]; - if session then - (session.log or log)("info", "Client disconnected: %s", err); - sm_destroy_session(session, err); - sessions[conn] = nil; - session = nil; - end -end - -function xmppclient.associate_session(conn, session) - sessions[conn] = session; -end - -connlisteners_register("xmppclient", xmppclient); -- cgit v1.2.3 From 494c61264c4bc9bce278d20a92685b78c68d2e4b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 23 Jan 2012 17:12:05 +0000 Subject: xmppserver_listener: Remove --- net/xmppserver_listener.lua | 209 -------------------------------------------- 1 file changed, 209 deletions(-) delete mode 100644 net/xmppserver_listener.lua (limited to 'net') diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua deleted file mode 100644 index 048c6c7d..00000000 --- a/net/xmppserver_listener.lua +++ /dev/null @@ -1,209 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - - -local tostring = tostring; -local type = type; -local xpcall = xpcall; -local s_format = string.format; -local traceback = debug.traceback; - -local logger = require "logger"; -local log = logger.init("xmppserver_listener"); -local st = require "util.stanza"; -local connlisteners_register = require "net.connlisteners".register; -local new_xmpp_stream = require "util.xmppstream".new; -local s2s_new_incoming = require "core.s2smanager".new_incoming; -local s2s_streamopened = require "core.s2smanager".streamopened; -local s2s_streamclosed = require "core.s2smanager".streamclosed; -local s2s_destroy_session = require "core.s2smanager".destroy_session; -local s2s_attempt_connect = require "core.s2smanager".attempt_connection; -local stream_callbacks = { default_ns = "jabber:server", - streamopened = s2s_streamopened, streamclosed = s2s_streamclosed, handlestanza = core_process_stanza }; - -local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; - -function stream_callbacks.error(session, error, data) - if error == "no-stream" then - session:close("invalid-namespace"); - elseif error == "parse-error" then - session.log("debug", "Server-to-server XML parse error: %s", tostring(error)); - session:close("not-well-formed"); - elseif error == "stream-error" then - local condition, text = "undefined-condition"; - for child in data:children() do - if child.attr.xmlns == xmlns_xmpp_streams then - if child.name ~= "text" then - condition = child.name; - else - text = child:get_text(); - end - if condition ~= "undefined-condition" and text then - break; - end - end - end - text = condition .. (text and (" ("..text..")") or ""); - session.log("info", "Session closed by remote with error: %s", text); - session:close(nil, text); - end -end - -local function handleerr(err) log("error", "Traceback[s2s]: %s: %s", tostring(err), traceback()); end -function stream_callbacks.handlestanza(session, stanza) - if stanza.attr.xmlns == "jabber:client" then --COMPAT: Prosody pre-0.6.2 may send jabber:client - stanza.attr.xmlns = nil; - end - stanza = session.filter("stanzas/in", stanza); - if stanza then - return xpcall(function () return core_process_stanza(session, stanza) end, handleerr); - end -end - -local sessions = {}; -local xmppserver = { default_port = 5269, default_mode = "*a", default_interface = "*" }; - --- These are session methods -- - -local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; -local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" }; -local function session_close(session, reason, remote_reason) - local log = session.log or log; - if session.conn then - if session.notopen then - session.sends2s(""); - session.sends2s(st.stanza("stream:stream", default_stream_attr):top_tag()); - end - if reason then - if type(reason) == "string" then -- assume stream error - log("info", "Disconnecting %s[%s], is: %s", session.host or "(unknown host)", session.type, reason); - session.sends2s(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); - elseif type(reason) == "table" then - if reason.condition then - local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up(); - if reason.text then - stanza:tag("text", stream_xmlns_attr):text(reason.text):up(); - end - if reason.extra then - stanza:add_child(reason.extra); - end - log("info", "Disconnecting %s[%s], is: %s", session.host or "(unknown host)", session.type, tostring(stanza)); - session.sends2s(stanza); - elseif reason.name then -- a stanza - log("info", "Disconnecting %s->%s[%s], is: %s", session.from_host or "(unknown host)", session.to_host or "(unknown host)", session.type, tostring(reason)); - session.sends2s(reason); - end - end - end - session.sends2s(""); - if session.notopen or not session.conn:close() then - session.conn:close(true); -- Force FIXME: timer? - end - session.conn:close(); - xmppserver.ondisconnect(session.conn, remote_reason or (reason and (reason.text or reason.condition)) or reason or "stream closed"); - end -end - - --- End of session methods -- - -local function initialize_session(session) - local stream = new_xmpp_stream(session, stream_callbacks); - session.stream = stream; - - session.notopen = true; - - function session.reset_stream() - session.notopen = true; - session.stream:reset(); - end - - local filter = session.filter; - function session.data(data) - data = filter("bytes/in", data); - if data then - local ok, err = stream:feed(data); - if ok then return; end - (session.log or log)("warn", "Received invalid XML: %s", data); - (session.log or log)("warn", "Problem was: %s", err); - session:close("not-well-formed"); - end - end - - session.close = session_close; - local handlestanza = stream_callbacks.handlestanza; - function session.dispatch_stanza(session, stanza) - return handlestanza(session, stanza); - end -end - -function xmppserver.onconnect(conn) - if not sessions[conn] then -- May be an existing outgoing session - local session = s2s_new_incoming(conn); - sessions[conn] = session; - - -- Logging functions -- - local conn_name = "s2sin"..tostring(conn):match("[a-f0-9]+$"); - session.log = logger.init(conn_name); - - session.log("info", "Incoming s2s connection"); - - initialize_session(session); - end -end - -function xmppserver.onincoming(conn, data) - local session = sessions[conn]; - if session then - session.data(data); - end -end - -function xmppserver.onstatus(conn, status) - if status == "ssl-handshake-complete" then - local session = sessions[conn]; - if session and session.direction == "outgoing" then - local to_host, from_host = session.to_host, session.from_host; - session.log("debug", "Sending stream header..."); - session.sends2s(s_format([[]], from_host, to_host)); - end - end -end - -function xmppserver.ondisconnect(conn, err) - local session = sessions[conn]; - if session then - if err and err ~= "closed" and session.type == "s2sout_unauthed" then - (session.log or log)("debug", "s2s connection attempt failed: %s", err); - if s2s_attempt_connect(session, err) then - (session.log or log)("debug", "...so we're going to try another target"); - return; -- Session lives for now - end - end - (session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err or "closed")); - s2s_destroy_session(session, err); - sessions[conn] = nil; - session = nil; - end -end - -function xmppserver.register_outgoing(conn, session) - session.direction = "outgoing"; - sessions[conn] = session; - - initialize_session(session); -end - -connlisteners_register("xmppserver", xmppserver); - - --- We need to perform some initialisation when a connection is created --- We also need to perform that same initialisation at other points (SASL, TLS, ...) - --- ...and we need to handle data --- ...and record all sessions associated with connections -- cgit v1.2.3 From 40423517a9c43d7e9c8c8879110ed03fe7aa28a9 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 23 Jan 2012 17:19:16 +0000 Subject: net.http, httpclient_listener: Merge listener into net.http --- net/http.lua | 52 +++++++++++++++++++++++++++++++---- net/httpclient_listener.lua | 66 --------------------------------------------- 2 files changed, 47 insertions(+), 71 deletions(-) delete mode 100644 net/httpclient_listener.lua (limited to 'net') diff --git a/net/http.lua b/net/http.lua index 6287f408..59f2c080 100644 --- a/net/http.lua +++ b/net/http.lua @@ -13,9 +13,6 @@ local httpstream_new = require "util.httpstream".new; local server = require "net.server" -local connlisteners_get = require "net.connlisteners".get; -local listener = connlisteners_get("httpclient") or error("No httpclient listener!"); - local t_insert, t_concat = table.insert, table.concat; local pairs, ipairs = pairs, ipairs; local tonumber, tostring, xpcall, select, debug_traceback, char, format = @@ -25,6 +22,52 @@ local log = require "util.logger".init("http"); module "http" +local requests = {}; -- Open requests + +local listener = { default_port = 80, default_mode = "*a" }; + +function listener.onconnect(conn) + local req = requests[conn]; + -- Send the request + local request_line = { req.method or "GET", " ", req.path, " HTTP/1.1\r\n" }; + if req.query then + t_insert(request_line, 4, "?"..req.query); + end + + conn:write(t_concat(request_line)); + local t = { [2] = ": ", [4] = "\r\n" }; + for k, v in pairs(req.headers) do + t[1], t[3] = k, v; + conn:write(t_concat(t)); + end + conn:write("\r\n"); + + if req.body then + conn:write(req.body); + end +end + +function listener.onincoming(conn, data) + local request = requests[conn]; + + if not request then + log("warn", "Received response from connection %s with no request attached!", tostring(conn)); + return; + end + + if data and request.reader then + request:reader(data); + end +end + +function listener.ondisconnect(conn, err) + local request = requests[conn]; + if request and request.conn then + request:reader(nil); + end + requests[conn] = nil; +end + function urlencode(s) return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end)); end function urldecode(s) return s and (s:gsub("%%(%x%x)", function (c) return char(tonumber(c,16)); end)); end @@ -152,8 +195,7 @@ function request(u, ex, callback) req.reader = request_reader; req.state = "status"; - listener.register_request(req.handler, req); - + requests[req.handler] = req; return req; end diff --git a/net/httpclient_listener.lua b/net/httpclient_listener.lua deleted file mode 100644 index c4e3c153..00000000 --- a/net/httpclient_listener.lua +++ /dev/null @@ -1,66 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -local log = require "util.logger".init("httpclient_listener"); -local t_concat, t_insert = table.concat, table.insert; - -local connlisteners_register = require "net.connlisteners".register; - -local requests = {}; -- Open requests -local buffers = {}; -- Buffers of partial lines - -local httpclient = { default_port = 80, default_mode = "*a" }; - -function httpclient.onconnect(conn) - local req = requests[conn]; - -- Send the request - local request_line = { req.method or "GET", " ", req.path, " HTTP/1.1\r\n" }; - if req.query then - t_insert(request_line, 4, "?"..req.query); - end - - conn:write(t_concat(request_line)); - local t = { [2] = ": ", [4] = "\r\n" }; - for k, v in pairs(req.headers) do - t[1], t[3] = k, v; - conn:write(t_concat(t)); - end - conn:write("\r\n"); - - if req.body then - conn:write(req.body); - end -end - -function httpclient.onincoming(conn, data) - local request = requests[conn]; - - if not request then - log("warn", "Received response from connection %s with no request attached!", tostring(conn)); - return; - end - - if data and request.reader then - request:reader(data); - end -end - -function httpclient.ondisconnect(conn, err) - local request = requests[conn]; - if request and request.conn then - request:reader(nil); - end - requests[conn] = nil; -end - -function httpclient.register_request(conn, req) - log("debug", "Attaching request %s to connection %s", tostring(req.id or req), tostring(conn)); - requests[conn] = req; -end - -connlisteners_register("httpclient", httpclient); -- cgit v1.2.3 From 06f2b0f3a44b915c20105405ddf3e550bdf25233 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 8 Apr 2012 04:09:33 +0500 Subject: net.http.{server|codes|parser}: Initial commit. --- net/http/codes.lua | 66 ++++++++++++++++ net/http/parser.lua | 116 +++++++++++++++++++++++++++ net/http/server.lua | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 405 insertions(+) create mode 100644 net/http/codes.lua create mode 100644 net/http/parser.lua create mode 100644 net/http/server.lua (limited to 'net') diff --git a/net/http/codes.lua b/net/http/codes.lua new file mode 100644 index 00000000..2e701027 --- /dev/null +++ b/net/http/codes.lua @@ -0,0 +1,66 @@ + +local response_codes = { + -- Source: http://www.iana.org/assignments/http-status-codes + -- s/^\(\d*\)\s*\(.*\S\)\s*\[RFC.*\]\s*$/^I["\1"] = "\2"; + [100] = "Continue"; + [101] = "Switching Protocols"; + [102] = "Processing"; + + [200] = "OK"; + [201] = "Created"; + [202] = "Accepted"; + [203] = "Non-Authoritative Information"; + [204] = "No Content"; + [205] = "Reset Content"; + [206] = "Partial Content"; + [207] = "Multi-Status"; + [208] = "Already Reported"; + [226] = "IM Used"; + + [300] = "Multiple Choices"; + [301] = "Moved Permanently"; + [302] = "Found"; + [303] = "See Other"; + [304] = "Not Modified"; + [305] = "Use Proxy"; + -- The 306 status code was used in a previous version of [RFC2616], is no longer used, and the code is reserved. + [307] = "Temporary Redirect"; + + [400] = "Bad Request"; + [401] = "Unauthorized"; + [402] = "Payment Required"; + [403] = "Forbidden"; + [404] = "Not Found"; + [405] = "Method Not Allowed"; + [406] = "Not Acceptable"; + [407] = "Proxy Authentication Required"; + [408] = "Request Timeout"; + [409] = "Conflict"; + [410] = "Gone"; + [411] = "Length Required"; + [412] = "Precondition Failed"; + [413] = "Request Entity Too Large"; + [414] = "Request-URI Too Long"; + [415] = "Unsupported Media Type"; + [416] = "Requested Range Not Satisfiable"; + [417] = "Expectation Failed"; + [422] = "Unprocessable Entity"; + [423] = "Locked"; + [424] = "Failed Dependency"; + -- The 425 status code is reserved for the WebDAV advanced collections expired proposal [RFC2817] + [426] = "Upgrade Required"; + + [500] = "Internal Server Error"; + [501] = "Not Implemented"; + [502] = "Bad Gateway"; + [503] = "Service Unavailable"; + [504] = "Gateway Timeout"; + [505] = "HTTP Version Not Supported"; + [506] = "Variant Also Negotiates"; -- Experimental + [507] = "Insufficient Storage"; + [508] = "Loop Detected"; + [510] = "Not Extended"; +}; + +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 }) diff --git a/net/http/parser.lua b/net/http/parser.lua new file mode 100644 index 00000000..c98c75af --- /dev/null +++ b/net/http/parser.lua @@ -0,0 +1,116 @@ + +local tonumber = tonumber; +local assert = assert; + +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 chunked; + local state = nil; + local packet; + local len; + local have_body; + local error; + return { + feed = function(self, data) + if error then return nil, "parse has failed"; end + if not data then -- EOF + if state and client and not len then -- reading client body until EOF + packet.body = buf; + success_cb(packet); + elseif buf ~= "" then -- unexpected EOF + error = true; return error_cb(); + end + return; + end + buf = buf..data; + while #buf > 0 do + if state == nil then -- read request + 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; + local first_line; + local headers = {}; + for line in buf:sub(1,index+1):gmatch("([^\r\n]+)\r\n") do -- parse request + if first_line then + local key, val = line:match("^([^%s:]+): *(.*)$"); + if not key then error = true; return error_cb("invalid-header-line"); end -- TODO handle multi-line and invalid headers + key = key:lower(); + headers[key] = headers[key] and headers[key]..","..val or val; + else + first_line = line; + if client then + httpversion, status_code, reason_phrase = line:match("^HTTP/(1%.[01]) (%d%d%d) (.*)$"); + if not status_code then error = true; return error_cb("invalid-status-line"); end + have_body = not + ( (options_cb and options_cb().method == "HEAD") + or (status_code == 204 or status_code == 304 or status_code == 301) + or (status_code >= 100 and status_code < 200) ); + chunked = have_body and headers["transfer-encoding"] == "chunked"; + else + method, path, httpversion = line:match("^(%w+) (%S+) HTTP/(1%.[01])$"); + if not method then error = true; return error_cb("invalid-status-line"); end + path = path:gsub("^//+", "/"); -- TODO parse url more + end + end + end + len = tonumber(headers["content-length"]); -- TODO check for invalid len + if client then + -- FIXME handle '100 Continue' response (by skipping it) + if not have_body then len = 0; end + packet = { + code = status_code; + httpversion = httpversion; + headers = headers; + body = have_body and "" or nil; + -- COMPAT the properties below are deprecated + responseversion = httpversion; + responseheaders = headers; + }; + else + len = len or 0; + packet = { + method = method; + path = path; + httpversion = httpversion; + headers = headers; + body = nil; + }; + end + buf = buf:sub(index + 4); + state = true; + end + if state then -- read body + if client then + if chunked then + local index = buf:find("\r\n", nil, true); + if not index then return; end -- not enough data + local chunk_size = buf:match("^%x+"); + if not chunk_size then error = true; return error_cb("invalid-chunk-size"); end + chunk_size = tonumber(chunk_size, 16); + index = index + 2; + if chunk_size == 0 then + state = nil; success_cb(packet); + elseif #buf - index + 1 >= chunk_size then -- we have a chunk + packet.body = packet.body..buf:sub(index, index + chunk_size - 1); + buf = buf:sub(index + chunk_size); + end + error("trailers"); -- FIXME MUST read trailers + elseif len and #buf >= len then + packet.body, buf = buf:sub(1, len), buf:sub(len + 1); + state = nil; success_cb(packet); + end + elseif #buf >= len then + packet.body, buf = buf:sub(1, len), buf:sub(len + 1); + state = nil; success_cb(packet); + end + end + end + end; + }; +end + +return httpstream; diff --git a/net/http/server.lua b/net/http/server.lua new file mode 100644 index 00000000..788f046b --- /dev/null +++ b/net/http/server.lua @@ -0,0 +1,223 @@ + +local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat; +local parser_new = require "net.http.parser".new; +local events = require "util.events".new(); +local addserver = require "net.server".addserver; +local log = require "util.logger".init("http.server"); +local os_date = os.date; +local pairs = pairs; +local s_upper = string.upper; +local setmetatable = setmetatable; +local xpcall = xpcall; +local debug = debug; +local tostring = tostring; +local codes = require "net.http.codes"; +local _G = _G; + +local _M = {}; + +local sessions = {}; +local handlers = {}; + +local listener = {}; + +local handle_request; +local _1, _2, _3; +local function _handle_request() return handle_request(_1, _2, _3); end +local function _traceback_handler(err) log("error", "Traceback[http]: %s: %s", tostring(err), debug.traceback()); end + +function listener.onconnect(conn) + local secure = conn:ssl() and true or nil; + local pending = {}; + local waiting = false; + local function process_next(last_response) + --if waiting then log("debug", "can't process_next, waiting"); return; end + if sessions[conn] and #pending > 0 then + local request = t_remove(pending); + --log("debug", "process_next: %s", request.path); + waiting = true; + --handle_request(conn, request, process_next); + _1, _2, _3 = conn, request, process_next; + if not xpcall(_handle_request, _traceback_handler) then + conn:write("HTTP/1.0 503 Internal Server Error\r\n\r\nAn error occured during the processing of this request."); + conn:close(); + end + else + --log("debug", "ready for more"); + waiting = false; + end + end + local function success_cb(request) + --log("debug", "success_cb: %s", request.path); + request.secure = secure; + t_insert(pending, request); + if not waiting then + process_next(); + end + end + local function error_cb(err) + log("debug", "error_cb: %s", err or ""); + -- FIXME don't close immediately, wait until we process current stuff + -- FIXME if err, send off a bad-request response + sessions[conn] = nil; + conn:close(); + end + sessions[conn] = parser_new(success_cb, error_cb); +end + +function listener.ondisconnect(conn) + sessions[conn] = nil; +end + +function listener.onincoming(conn, data) + sessions[conn]:feed(data); +end + +local headerfix = setmetatable({}, { + __index = function(t, k) + local v = "\r\n"..k:gsub("_", "-"):gsub("%f[%w].", s_upper)..": "; + t[k] = v; + return v; + end +}); + +function _M.hijack_response(response, listener) + error("TODO"); +end +function handle_request(conn, request, finish_cb) + --log("debug", "handler: %s", request.path); + local headers = {}; + for k,v in pairs(request.headers) do headers[k:gsub("-", "_")] = v; end + request.headers = headers; + request.conn = conn; + + local date_header = os_date('!%a, %d %b %Y %H:%M:%S GMT'); -- FIXME use + local conn_header = request.headers.connection; + local keep_alive = conn_header == "Keep-Alive" or (request.httpversion == "1.1" and conn_header ~= "close"); + + local response = { + request = request; + status_code = 200; + headers = { date = date_header, connection = (keep_alive and "Keep-Alive" or "close") }; + conn = conn; + send = _M.send_response; + finish_cb = finish_cb; + }; + + if not request.headers.host then + response.status_code = 400; + response.headers.content_type = "text/html"; + response:send("400 Bad Request400 Bad Request: No Host header."); + else + -- TODO call handler + --response.headers.content_type = "text/plain"; + --response:send("host="..(request.headers.host or "").."\npath="..request.path.."\n"..(request.body or "")); + local host = request.headers.host; + if host then + host = host:match("[^:]*"):lower(); + local event = request.method.." "..host..request.path:match("[^?]*"); + local payload = { request = request, response = response }; + --[[repeat + if events.fire_event(event, payload) ~= nil then return; end + event = (event:sub(-1) == "/") and event:sub(1, -1) or event:gsub("[^/]*$", ""); + if event:sub(-1) == "/" then + event = event:sub(1, -1); + else + event = event:gsub("[^/]*$", ""); + end + until not event:find("/", 1, true);]] + --log("debug", "Event: %s", event); + if events.fire_event(event, payload) ~= nil then return; end + -- TODO try adding/stripping / at the end, but this needs to work via an HTTP redirect + end + + -- if handler not called, fallback to legacy httpserver handlers + _M.legacy_handler(request, response); + end +end +function _M.send_response(response, body) + local status_line = "HTTP/"..response.request.httpversion.." "..(response.status or codes[response.status_code]); + local headers = response.headers; + body = body or ""; + headers.content_length = #body; + + local output = { status_line }; + for k,v in pairs(headers) do + t_insert(output, headerfix[k]..v); + end + t_insert(output, "\r\n\r\n"); + t_insert(output, body); + + response.conn:write(t_concat(output)); + if headers.connection == "Keep-Alive" then + response:finish_cb(); + else + response.conn:close(); + end +end +function _M.legacy_handler(request, response) + log("debug", "Invoking legacy handler"); + local base = request.path:match("^/([^/?]+)"); + local legacy_server = _G.httpserver and _G.httpserver.new.http_servers[5280]; + local handler = legacy_server and legacy_server.handlers[base]; + if not handler then handler = _G.httpserver and _G.httpserver.set_default_handler.default_handler; end + if handler then + -- add legacy properties to request object + request.url = { path = request.path }; + request.handler = response.conn; + request.id = tostring{}:match("%x+$"); + local headers = {}; + for k,v in pairs(request.headers) do + headers[k:gsub("_", "-")] = v; + end + request.headers = headers; + function request:send(resp) + if self.destroyed then return; end + if resp.body or resp.headers then + if resp.headers then + for k,v in pairs(resp.headers) do response.headers[k] = v; end + end + response:send(resp.body) + else + response:send(resp) + end + self.sent = true; + self:destroy(); + end + function request:destroy() + if self.destroyed then return; end + if not self.sent then return self:send(""); end + self.destroyed = true; + if self.on_destroy then + log("debug", "Request has destroy callback"); + self:on_destroy(); + else + log("debug", "Request has no destroy callback"); + end + end + local r = handler(request.method, request.body, request); + if r ~= true then + request:send(r); + end + else + log("debug", "No handler found"); + response.status_code = 404; + response.headers.content_type = "text/html"; + response:send("404 Not Found404 Not Found: No such page."); + end +end + +function _M.add_handler(event, handler, priority) + events.add_handler(event, handler, priority); +end +function _M.remove_handler(event, handler) + events.remove_handler(event, handler); +end + +function _M.listen_on(port, interface, ssl) + addserver(interface or "*", port, listener, "*a", ssl); +end + +_M.listener = listener; +_M.codes = codes; +return _M; -- cgit v1.2.3 From becd794524489f5888069d1dc6612600e7d7a80e Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sat, 21 Apr 2012 17:37:00 +0500 Subject: net.http.server: Missing in 404 Not Found response. --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 788f046b..feb8f766 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -203,7 +203,7 @@ function _M.legacy_handler(request, response) log("debug", "No handler found"); response.status_code = 404; response.headers.content_type = "text/html"; - response:send("<html><head>404 Not Found</head><body>404 Not Found: No such page.</body></html>"); + response:send("<html><head><title>404 Not Found404 Not Found: No such page."); end end -- cgit v1.2.3 From 59bd215bb29f37b2bbf809728f1d894a9ce112a4 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sat, 21 Apr 2012 17:38:01 +0500 Subject: net.http.server: Fire global HTTP event when no specific handlers available. --- net/http/server.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index feb8f766..1f61c7b9 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -129,6 +129,7 @@ function handle_request(conn, request, finish_cb) --log("debug", "Event: %s", event); if events.fire_event(event, payload) ~= nil then return; end -- TODO try adding/stripping / at the end, but this needs to work via an HTTP redirect + if events.fire_event("*", payload) ~= nil then return; end end -- if handler not called, fallback to legacy httpserver handlers -- cgit v1.2.3 From 6320d988ecc36775611d4a05fb621020329cfc25 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 21 Apr 2012 16:27:42 +0100 Subject: net.connlisteners: Be gone! --- net/connlisteners.lua | 81 --------------------------------------------------- 1 file changed, 81 deletions(-) delete mode 100644 net/connlisteners.lua (limited to 'net') diff --git a/net/connlisteners.lua b/net/connlisteners.lua deleted file mode 100644 index 6a227c9d..00000000 --- a/net/connlisteners.lua +++ /dev/null @@ -1,81 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - - - -local listeners_dir = (CFG_SOURCEDIR or ".").."/net/"; -local server = require "net.server"; -local log = require "util.logger".init("connlisteners"); -local tostring = tostring; -local type = type -local ipairs = ipairs - -local dofile, xpcall, error = - dofile, xpcall, error - -local debug_traceback = debug.traceback; - -module "connlisteners" - -local listeners = {}; - -function register(name, listener) - if listeners[name] and listeners[name] ~= listener then - log("debug", "Listener %s is already registered, not registering any more", name); - return false; - end - listeners[name] = listener; - log("debug", "Registered connection listener %s", name); - return true; -end - -function deregister(name) - listeners[name] = nil; -end - -function get(name) - local h = listeners[name]; - if not h then - local ok, ret = xpcall(function() dofile(listeners_dir..name:gsub("[^%w%-]", "_").."_listener.lua") end, debug_traceback); - if not ok then - log("error", "Error while loading listener '%s': %s", tostring(name), tostring(ret)); - return nil, ret; - end - h = listeners[name]; - end - return h; -end - -function start(name, udata) - local h, err = get(name); - if not h then - error("No such connection module: "..name.. (err and (" ("..err..")") or ""), 0); - end - - local interfaces = (udata and udata.interface) or h.default_interface or "*"; - if type(interfaces) == "string" then interfaces = {interfaces}; end - local port = (udata and udata.port) or h.default_port or error("Can't start listener "..name.." because no port was specified, and it has no default port", 0); - local mode = (udata and udata.mode) or h.default_mode or 1; - local ssl = (udata and udata.ssl) or nil; - local autossl = udata and udata.type == "ssl"; - - if autossl and not ssl then - return nil, "no ssl context"; - end - - ok, err = true, {}; - for _, interface in ipairs(interfaces) do - local handler - handler, err[interface] = server.addserver(interface, port, h, mode, autossl and ssl or nil); - ok = ok and handler; - end - - return ok, err; -end - -return _M; -- cgit v1.2.3 From 9d478011222d360bb8d7bdaccd94da0e9e331621 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 21 Apr 2012 22:50:57 +0100 Subject: mod_component: Make a shared module, and move the xmppcomponent_listener into it ('port'ing over to portmanager). Ha ha. --- net/xmppcomponent_listener.lua | 218 ----------------------------------------- 1 file changed, 218 deletions(-) delete mode 100644 net/xmppcomponent_listener.lua (limited to 'net') diff --git a/net/xmppcomponent_listener.lua b/net/xmppcomponent_listener.lua deleted file mode 100644 index dd7b2b91..00000000 --- a/net/xmppcomponent_listener.lua +++ /dev/null @@ -1,218 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - - -local t_concat = table.concat; -local tostring = tostring; -local type = type; -local pairs = pairs; - -local lxp = require "lxp"; -local logger = require "util.logger"; -local config = require "core.configmanager"; -local connlisteners = require "net.connlisteners"; -local uuid_gen = require "util.uuid".generate; -local jid_split = require "util.jid".split; -local sha1 = require "util.hashes".sha1; -local st = require "util.stanza"; -local new_xmpp_stream = require "util.xmppstream".new; - -local sessions = {}; - -local log = logger.init("componentlistener"); - -local component_listener = { default_port = 5347; default_mode = "*a"; default_interface = config.get("*", "core", "component_interface") or "127.0.0.1" }; - -local xmlns_component = 'jabber:component:accept'; - ---- Callbacks/data for xmppstream to handle streams for us --- - -local stream_callbacks = { default_ns = xmlns_component }; - -local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; - -function stream_callbacks.error(session, error, data, data2) - if session.destroyed then return; end - log("warn", "Error processing component stream: "..tostring(error)); - if error == "no-stream" then - session:close("invalid-namespace"); - elseif error == "parse-error" then - session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(data)); - session:close("not-well-formed"); - elseif error == "stream-error" then - local condition, text = "undefined-condition"; - for child in data:children() do - if child.attr.xmlns == xmlns_xmpp_streams then - if child.name ~= "text" then - condition = child.name; - else - text = child:get_text(); - end - if condition ~= "undefined-condition" and text then - break; - end - end - end - text = condition .. (text and (" ("..text..")") or ""); - session.log("info", "Session closed by remote with error: %s", text); - session:close(nil, text); - end -end - -function stream_callbacks.streamopened(session, attr) - if config.get(attr.to, "core", "component_module") ~= "component" then - -- Trying to act as a component domain which - -- hasn't been configured - session:close{ condition = "host-unknown", text = tostring(attr.to).." does not match any configured external components" }; - return; - end - - -- Note that we don't create the internal component - -- until after the external component auths successfully - - session.host = attr.to; - session.streamid = uuid_gen(); - session.notopen = nil; - - session.send(st.stanza("stream:stream", { xmlns=xmlns_component, - ["xmlns:stream"]='http://etherx.jabber.org/streams', id=session.streamid, from=session.host }):top_tag()); - -end - -function stream_callbacks.streamclosed(session) - session.log("debug", "Received "); - session:close(); -end - -local core_process_stanza = core_process_stanza; - -function stream_callbacks.handlestanza(session, stanza) - -- Namespaces are icky. - if not stanza.attr.xmlns and stanza.name == "handshake" then - stanza.attr.xmlns = xmlns_component; - end - if not stanza.attr.xmlns or stanza.attr.xmlns == "jabber:client" then - local from = stanza.attr.from; - if from then - if session.component_validate_from then - local _, domain = jid_split(stanza.attr.from); - if domain ~= session.host then - -- Return error - session.log("warn", "Component sent stanza with missing or invalid 'from' address"); - session:close{ - condition = "invalid-from"; - text = "Component tried to send from address <"..tostring(from) - .."> which is not in domain <"..tostring(session.host)..">"; - }; - return; - end - end - else - stanza.attr.from = session.host; - end - if not stanza.attr.to then - session.log("warn", "Rejecting stanza with no 'to' address"); - session.send(st.error_reply(stanza, "modify", "bad-request", "Components MUST specify a 'to' address on stanzas")); - return; - end - end - return core_process_stanza(session, stanza); -end - ---- Closing a component connection -local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; -local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" }; -local function session_close(session, reason) - if session.destroyed then return; end - local log = session.log or log; - if session.conn then - if session.notopen then - session.send(""); - session.send(st.stanza("stream:stream", default_stream_attr):top_tag()); - end - if reason then - if type(reason) == "string" then -- assume stream error - log("info", "Disconnecting component, is: %s", reason); - session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); - elseif type(reason) == "table" then - if reason.condition then - local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up(); - if reason.text then - stanza:tag("text", stream_xmlns_attr):text(reason.text):up(); - end - if reason.extra then - stanza:add_child(reason.extra); - end - log("info", "Disconnecting component, is: %s", tostring(stanza)); - session.send(stanza); - elseif reason.name then -- a stanza - log("info", "Disconnecting component, is: %s", tostring(reason)); - session.send(reason); - end - end - end - session.send(""); - session.conn:close(); - component_listener.ondisconnect(session.conn, "stream error"); - end -end - ---- Component connlistener -function component_listener.onconnect(conn) - local _send = conn.write; - local session = { type = "component", conn = conn, send = function (data) return _send(conn, tostring(data)); end }; - - -- Logging functions -- - local conn_name = "jcp"..tostring(conn):match("[a-f0-9]+$"); - session.log = logger.init(conn_name); - session.close = session_close; - - session.log("info", "Incoming Jabber component connection"); - - local stream = new_xmpp_stream(session, stream_callbacks); - session.stream = stream; - - session.notopen = true; - - function session.reset_stream() - session.notopen = true; - session.stream:reset(); - end - - function session.data(conn, data) - local ok, err = stream:feed(data); - if ok then return; end - log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); - session:close("not-well-formed"); - end - - session.dispatch_stanza = stream_callbacks.handlestanza; - - sessions[conn] = session; -end -function component_listener.onincoming(conn, data) - local session = sessions[conn]; - session.data(conn, data); -end -function component_listener.ondisconnect(conn, err) - local session = sessions[conn]; - if session then - (session.log or log)("info", "component disconnected: %s (%s)", tostring(session.host), tostring(err)); - if session.on_destroy then session:on_destroy(err); end - sessions[conn] = nil; - for k in pairs(session) do - if k ~= "log" and k ~= "close" then - session[k] = nil; - end - end - session.destroyed = true; - session = nil; - end -end - -connlisteners.register('xmppcomponent', component_listener); -- cgit v1.2.3 From b90b319b82362a71fa26e706aff9ec1f9a48c8e0 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 21 Apr 2012 22:54:55 +0100 Subject: multiplex_listener: Remove (already ported to mod_net_multiplex) --- net/multiplex_listener.lua | 50 ---------------------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 net/multiplex_listener.lua (limited to 'net') diff --git a/net/multiplex_listener.lua b/net/multiplex_listener.lua deleted file mode 100644 index b515ccce..00000000 --- a/net/multiplex_listener.lua +++ /dev/null @@ -1,50 +0,0 @@ - -local connlisteners_register = require "net.connlisteners".register; -local connlisteners_get = require "net.connlisteners".get; - -local httpserver_listener = connlisteners_get("httpserver"); -local xmppserver_listener = connlisteners_get("xmppserver"); -local xmppclient_listener = connlisteners_get("xmppclient"); -local xmppcomponent_listener = connlisteners_get("xmppcomponent"); - -local server = { default_mode = "*a" }; - -local buffer = {}; - -function server.onincoming(conn, data) - if not data then return; end - local buf = buffer[conn]; - buffer[conn] = nil; - buf = buf and buf..data or data; - if buf:match("^[a-zA-Z]") then - local listener = httpserver_listener; - conn:setlistener(listener); - local onconnect = listener.onconnect; - if onconnect then onconnect(conn) end - listener.onincoming(conn, buf); - elseif buf:match(">") then - local listener; - local xmlns = buf:match("%sxmlns%s*=%s*['\"]([^'\"]*)"); - if xmlns == "jabber:server" then - listener = xmppserver_listener; - elseif xmlns == "jabber:component:accept" then - listener = xmppcomponent_listener; - else - listener = xmppclient_listener; - end - conn:setlistener(listener); - local onconnect = listener.onconnect; - if onconnect then onconnect(conn) end - listener.onincoming(conn, buf); - elseif #buf > 1024 then - conn:close(); - else - buffer[conn] = buf; - end -end - -function server.ondisconnect(conn, err) - buffer[conn] = nil; -- warn if no buffer? -end - -connlisteners_register("multiplex", server); -- cgit v1.2.3 From 1e7af784820756180d503a34fd86d4f685d42f65 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 22 Apr 2012 23:43:34 +0500 Subject: net.httpserver: Comment dependency on connlisteners. Further cleanup to follow. --- net/httpserver.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/httpserver.lua b/net/httpserver.lua index 44e8e24d..0f5a4186 100644 --- a/net/httpserver.lua +++ b/net/httpserver.lua @@ -10,8 +10,8 @@ local url_parse = require "socket.url".parse; local httpstream_new = require "util.httpstream".new; -local connlisteners_start = require "net.connlisteners".start; -local connlisteners_get = require "net.connlisteners".get; +--local connlisteners_start = require "net.connlisteners".start; +--local connlisteners_get = require "net.connlisteners".get; local listener; local t_insert, t_concat = table.insert, table.concat; @@ -164,7 +164,7 @@ end function destroy_request(request) log("debug", "Destroying request %s", request.id); - listener = listener or connlisteners_get("httpserver"); + --listener = listener or connlisteners_get("httpserver"); if not request.destroyed then request.destroyed = true; if request.on_destroy then @@ -186,7 +186,7 @@ function new(params) http_server = { handlers = {} }; http_servers[params.port] = http_server; -- We weren't already listening on this port, so start now - connlisteners_start("httpserver", params); + --connlisteners_start("httpserver", params); end if params.base then http_server.handlers[params.base] = params.handler; -- cgit v1.2.3 From c065013cedb83885226e5870a34cf4c2add53450 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sun, 22 Apr 2012 23:44:21 +0500 Subject: net.http.server: Fix legacy net.httpserver fallback (httpserver is no longer a global). --- net/http/server.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 1f61c7b9..3a0cb53a 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -13,6 +13,7 @@ local debug = debug; local tostring = tostring; local codes = require "net.http.codes"; local _G = _G; +local legacy_httpserver = require "net.httpserver"; local _M = {}; @@ -159,9 +160,9 @@ end function _M.legacy_handler(request, response) log("debug", "Invoking legacy handler"); local base = request.path:match("^/([^/?]+)"); - local legacy_server = _G.httpserver and _G.httpserver.new.http_servers[5280]; + local legacy_server = legacy_httpserver and legacy_httpserver.new.http_servers[5280]; local handler = legacy_server and legacy_server.handlers[base]; - if not handler then handler = _G.httpserver and _G.httpserver.set_default_handler.default_handler; end + if not handler then handler = legacy_httpserver and legacy_httpserver.set_default_handler.default_handler; end if handler then -- add legacy properties to request object request.url = { path = request.path }; -- cgit v1.2.3 From f2b41269670e6947a2f43c3d793cac9b56bccf02 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 23 Apr 2012 21:29:18 +0100 Subject: net.http.server: Support for wildcard events (events that end with '/*') --- net/http/server.lua | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 3a0cb53a..94487e5e 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -22,6 +22,57 @@ local handlers = {}; local listener = {}; +local function is_wildcard_event(event) + return event:sub(-2, -1) == "/*"; +end +local function is_wildcard_match(wildcard_event, event) + log("debug", "comparing %q with %q", wildcard_event:sub(1, -2), event:sub(1, #wildcard_event-1)); + return wildcard_event:sub(1, -2) == event:sub(1, #wildcard_event-1); +end + +local event_map = events._event_map; +setmetatable(events._handlers, { + __index = function (handlers, curr_event) + if is_wildcard_event(curr_event) then return; end -- Wildcard events cannot be fired + -- Find all handlers that could match this event, sort them + -- and then put the array into handlers[event] + local matching_handlers_set = {}; + local handlers_array = {}; + for event, handlers_set in pairs(event_map) do + if event == curr_event or + is_wildcard_event(event) and is_wildcard_match(event, curr_event) then + for handler, priority in pairs(handlers_set) do + matching_handlers_set[handler] = { (select(2, event:gsub("/", "%1"))), priority }; + table.insert(handlers_array, handler); + end + end + end + if #handlers_array == 0 then return; end + table.sort(handlers_array, function(b, a) + local a_score, b_score = matching_handlers_set[a], matching_handlers_set[b]; + for i = 1, #a_score do + if a ~= b then -- If equal, compare next score value + return a_score[i] < b_score[i]; + end + end + return false; + end); + handlers[curr_event] = handlers_array; + return handlers_array; + end; + __newindex = function (handlers, curr_event, handlers_array) + if handlers_array == nil + and is_wildcard_event(curr_event) then + -- Invalidate all matching + for event in pairs(handlers) do + if is_wildcard_match(curr_event, event) then + handlers[event] = nil; + end + end + end + end; +}); + local handle_request; local _1, _2, _3; local function _handle_request() return handle_request(_1, _2, _3); end -- cgit v1.2.3 From f56e37130911b81877bc151bc96139efbdc504e2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 24 Apr 2012 15:42:35 +0100 Subject: net.server_select: Remove server from _server table when closing --- net/server_select.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index 8802f620..d6cfc1f8 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -202,6 +202,7 @@ wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, maxco socket:close( ) _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) _readlistlen = removesocket( _readlist, socket, _readlistlen ) + _server[ip..":"..serverport] = nil; _socketlist[ socket ] = nil handler = nil socket = nil -- cgit v1.2.3 From 824fdebc5566bae7fe69811bff0d1b4517a78925 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 24 Apr 2012 15:52:30 +0100 Subject: net.server_event: Do not automatically close clients when closing a server port --- net/server_event.lua | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/server_event.lua b/net/server_event.lua index dbf5161f..8d6f5597 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -343,24 +343,11 @@ do return nil, "writebuffer not empty, waiting" end else - debug( "try to close server with id:", self.id, "args:", now ) + debug( "try to close server with id:", tostring(self.id), "args:", tostring(now) ) self.fatalerror = "server to close" self:_lock( true ) - local count = 0 - for _, item in ipairs( interfacelist( ) ) do - if ( item.type ~= "server" ) and ( item._server == self ) then -- client/server match - if item:close( now ) then -- writebuffer was empty - count = count + 1 - end - end - end - local timeout = 0 -- dont wait for unfinished writebuffers of clients... - if not now then - timeout = cfg.WRITE_TIMEOUT -- ...or wait for it - end - self:_close( timeout ) -- add new event to remove the server interface - debug( "seconds remained until server is closed:", timeout ) - return count -- returns finished clients with empty writebuffer + self:_close( 0 ) -- add new event to remove the server interface + return true end end -- cgit v1.2.3 From 37f43d0189e9702406bfaf97e8b616f1dd783648 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 24 Apr 2012 19:05:45 +0100 Subject: net.http.server: Remove debug message --- net/http/server.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 94487e5e..50a5c5a1 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -26,7 +26,6 @@ local function is_wildcard_event(event) return event:sub(-2, -1) == "/*"; end local function is_wildcard_match(wildcard_event, event) - log("debug", "comparing %q with %q", wildcard_event:sub(1, -2), event:sub(1, #wildcard_event-1)); return wildcard_event:sub(1, -2) == event:sub(1, #wildcard_event-1); end -- cgit v1.2.3 From 7cb22f77a78741a1bd085c6b3dc3b31f51c1fa09 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 24 Apr 2012 19:07:12 +0100 Subject: net.http.server: Handle results returned by handlers, and send as a response. Also removes explicit firing of '*', which can now be done via wildcard events. --- net/http/server.lua | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 50a5c5a1..185ac9a0 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -168,19 +168,27 @@ function handle_request(conn, request, finish_cb) host = host:match("[^:]*"):lower(); local event = request.method.." "..host..request.path:match("[^?]*"); local payload = { request = request, response = response }; - --[[repeat - if events.fire_event(event, payload) ~= nil then return; end - event = (event:sub(-1) == "/") and event:sub(1, -1) or event:gsub("[^/]*$", ""); - if event:sub(-1) == "/" then - event = event:sub(1, -1); - else - event = event:gsub("[^/]*$", ""); + --log("debug", "Firing event: %s", event); + local result = events.fire_event(event, payload); + if result ~= nil then + if result ~= true then + local code, body = 200, ""; + local result_type = type(result); + if result_type == "number" then + response.status_code = result; + elseif result_type == "string" then + body = result; + elseif result_type == "table" then + body = result.body; + result.body = nil; + for k, v in pairs(result) do + response[k] = v; + end + end + response:send(body); end - until not event:find("/", 1, true);]] - --log("debug", "Event: %s", event); - if events.fire_event(event, payload) ~= nil then return; end - -- TODO try adding/stripping / at the end, but this needs to work via an HTTP redirect - if events.fire_event("*", payload) ~= nil then return; end + return; + end end -- if handler not called, fallback to legacy httpserver handlers -- cgit v1.2.3 From 8e4f5391a268fbd3d80d2de2f57a111aa2937bf6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 25 Apr 2012 14:58:10 +0100 Subject: net.http.server: Remove legacy compatibility --- net/http/server.lua | 61 ++++------------------------------------------------- 1 file changed, 4 insertions(+), 57 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 185ac9a0..00571bce 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -160,9 +160,6 @@ function handle_request(conn, request, finish_cb) response.headers.content_type = "text/html"; response:send("400 Bad Request400 Bad Request: No Host header."); else - -- TODO call handler - --response.headers.content_type = "text/plain"; - --response:send("host="..(request.headers.host or "").."\npath="..request.path.."\n"..(request.body or "")); local host = request.headers.host; if host then host = host:match("[^:]*"):lower(); @@ -191,8 +188,10 @@ function handle_request(conn, request, finish_cb) end end - -- if handler not called, fallback to legacy httpserver handlers - _M.legacy_handler(request, response); + -- if handler not called, return 404 + response.status_code = 404; + response.headers.content_type = "text/html"; + response:send("404 Not Found404 Not Found: No such page."); end end function _M.send_response(response, body) @@ -215,58 +214,6 @@ function _M.send_response(response, body) response.conn:close(); end end -function _M.legacy_handler(request, response) - log("debug", "Invoking legacy handler"); - local base = request.path:match("^/([^/?]+)"); - local legacy_server = legacy_httpserver and legacy_httpserver.new.http_servers[5280]; - local handler = legacy_server and legacy_server.handlers[base]; - if not handler then handler = legacy_httpserver and legacy_httpserver.set_default_handler.default_handler; end - if handler then - -- add legacy properties to request object - request.url = { path = request.path }; - request.handler = response.conn; - request.id = tostring{}:match("%x+$"); - local headers = {}; - for k,v in pairs(request.headers) do - headers[k:gsub("_", "-")] = v; - end - request.headers = headers; - function request:send(resp) - if self.destroyed then return; end - if resp.body or resp.headers then - if resp.headers then - for k,v in pairs(resp.headers) do response.headers[k] = v; end - end - response:send(resp.body) - else - response:send(resp) - end - self.sent = true; - self:destroy(); - end - function request:destroy() - if self.destroyed then return; end - if not self.sent then return self:send(""); end - self.destroyed = true; - if self.on_destroy then - log("debug", "Request has destroy callback"); - self:on_destroy(); - else - log("debug", "Request has no destroy callback"); - end - end - local r = handler(request.method, request.body, request); - if r ~= true then - request:send(r); - end - else - log("debug", "No handler found"); - response.status_code = 404; - response.headers.content_type = "text/html"; - response:send("404 Not Found404 Not Found: No such page."); - end -end - function _M.add_handler(event, handler, priority) events.add_handler(event, handler, priority); end -- cgit v1.2.3 From b6ef379c9ae161aca2184c7179cec737988227ca Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 25 Apr 2012 15:02:27 +0100 Subject: net.http.server: Small fix to comment --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 00571bce..dc7c5a06 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -34,7 +34,7 @@ setmetatable(events._handlers, { __index = function (handlers, curr_event) if is_wildcard_event(curr_event) then return; end -- Wildcard events cannot be fired -- Find all handlers that could match this event, sort them - -- and then put the array into handlers[event] + -- and then put the array into handlers[curr_event] (and return it) local matching_handlers_set = {}; local handlers_array = {}; for event, handlers_set in pairs(event_map) do -- cgit v1.2.3 From 15585ed873feaa58d5944bce5b861a619c2a63af Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 25 Apr 2012 23:08:33 +0100 Subject: net.http.server: Support for on_destroy callback on response objects, and a 'finished' flag to say when they are destroyed (responded to or connection closed) --- net/http/server.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index dc7c5a06..c108a398 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -117,6 +117,11 @@ function listener.onconnect(conn) end function listener.ondisconnect(conn) + local open_response = conn._http_open_response; + if open_response and open_response.on_destroy then + open_response.finished = true; + open_response:on_destroy(); + end sessions[conn] = nil; end @@ -154,6 +159,7 @@ function handle_request(conn, request, finish_cb) send = _M.send_response; finish_cb = finish_cb; }; + conn._http_open_response = response; if not request.headers.host then response.status_code = 400; @@ -195,6 +201,10 @@ function handle_request(conn, request, finish_cb) end end function _M.send_response(response, body) + if response.finished then return; end + response.finished = true; + response.conn._http_open_response = nil; + local status_line = "HTTP/"..response.request.httpversion.." "..(response.status or codes[response.status_code]); local headers = response.headers; body = body or ""; @@ -208,6 +218,10 @@ function _M.send_response(response, body) t_insert(output, body); response.conn:write(t_concat(output)); + if response.on_destroy then + response:on_destroy(); + response.on_destroy = nil; + end if headers.connection == "Keep-Alive" then response:finish_cb(); else -- cgit v1.2.3 From 37840f043cbe439e89ea82dbb34c208f47845ce0 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 26 Apr 2012 04:24:43 +0100 Subject: net.http.server: Fix to compare priority if path lengths are the same (logic fail) --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index c108a398..58554f39 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -50,7 +50,7 @@ setmetatable(events._handlers, { table.sort(handlers_array, function(b, a) local a_score, b_score = matching_handlers_set[a], matching_handlers_set[b]; for i = 1, #a_score do - if a ~= b then -- If equal, compare next score value + if a_score[i] ~= b_score[i] then -- If equal, compare next score value return a_score[i] < b_score[i]; end end -- cgit v1.2.3 From dbb3dc6a0112bac19582c811a788254e3cacef41 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 26 Apr 2012 06:47:17 +0100 Subject: net.http.server: Lower score of wildcard handlers to ensure specific handlers beat them --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 58554f39..906b3eaf 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -41,7 +41,7 @@ setmetatable(events._handlers, { if event == curr_event or is_wildcard_event(event) and is_wildcard_match(event, curr_event) then for handler, priority in pairs(handlers_set) do - matching_handlers_set[handler] = { (select(2, event:gsub("/", "%1"))), priority }; + matching_handlers_set[handler] = { (select(2, event:gsub("/", "%1"))), is_wildcard_event(event) and 0 or 1, priority }; table.insert(handlers_array, handler); end end -- cgit v1.2.3 From 2415fcd5c23fc0d5a4f42078eb96394a10f11872 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 26 Apr 2012 06:58:57 +0100 Subject: net.http.server: Expose events object (for debug purposes) --- net/http/server.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 906b3eaf..d6c3a03a 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -241,4 +241,5 @@ end _M.listener = listener; _M.codes = codes; +_M._events = events; return _M; -- cgit v1.2.3 From e3433dca1d7218f37066a50908cd46744914c70e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 26 Apr 2012 15:05:05 +0100 Subject: net.server.http: Parse absolute URIs in requests (thanks Maranda) --- net/http/server.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index d6c3a03a..4f9e1463 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -1,6 +1,7 @@ local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat; local parser_new = require "net.http.parser".new; +local url_parse = require "socket.url".parse; local events = require "util.events".new(); local addserver = require "net.server".addserver; local log = require "util.logger".init("http.server"); @@ -101,6 +102,9 @@ function listener.onconnect(conn) local function success_cb(request) --log("debug", "success_cb: %s", request.path); request.secure = secure; + local parsed_dest = url_parse(request.path); + request.url = parsed_dest; + request.path = parsed_dest.path; t_insert(pending, request); if not waiting then process_next(); -- cgit v1.2.3 From 8edd8e0e8d2fa4177f6508d3b21a31f5e78f4aa1 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 26 Apr 2012 15:14:19 +0100 Subject: net.http.server: Make error handling overrideable via 'http-error' event --- net/http/server.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 4f9e1463..deaa44cd 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -76,7 +76,12 @@ setmetatable(events._handlers, { local handle_request; local _1, _2, _3; local function _handle_request() return handle_request(_1, _2, _3); end -local function _traceback_handler(err) log("error", "Traceback[http]: %s: %s", tostring(err), debug.traceback()); end + +local last_err; +local function _traceback_handler(err) last_err = err; log("error", "Traceback[http]: %s: %s", tostring(err), debug.traceback()); end +events.add_handler("http-error", function (error) + return "Error processing request: "..codes[error.code]..". Check your error log for more information."; +end, -1); function listener.onconnect(conn) local secure = conn:ssl() and true or nil; @@ -91,7 +96,7 @@ function listener.onconnect(conn) --handle_request(conn, request, process_next); _1, _2, _3 = conn, request, process_next; if not xpcall(_handle_request, _traceback_handler) then - conn:write("HTTP/1.0 503 Internal Server Error\r\n\r\nAn error occured during the processing of this request."); + conn:write("HTTP/1.0 500 Internal Server Error\r\n\r\n"..events.fire_event("http-error", { code = 500, private_message = last_err })); conn:close(); end else @@ -168,7 +173,7 @@ function handle_request(conn, request, finish_cb) if not request.headers.host then response.status_code = 400; response.headers.content_type = "text/html"; - response:send("400 Bad Request400 Bad Request: No Host header."); + response:send(events.fire_event("http-error", { code = 400, message = "No 'Host' header" })); else local host = request.headers.host; if host then @@ -183,6 +188,9 @@ function handle_request(conn, request, finish_cb) local result_type = type(result); if result_type == "number" then response.status_code = result; + if result >= 400 then + body = events.fire_event("http-error", { code = result }); + end elseif result_type == "string" then body = result; elseif result_type == "table" then @@ -201,7 +209,7 @@ function handle_request(conn, request, finish_cb) -- if handler not called, return 404 response.status_code = 404; response.headers.content_type = "text/html"; - response:send("404 Not Found404 Not Found: No such page."); + response:send(events.fire_event("http-error", { code = 404 })); end end function _M.send_response(response, body) -- cgit v1.2.3 From b0b093e7264da1a620a2f4e9101e1b676ea1db0e Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Thu, 26 Apr 2012 20:07:13 +0500 Subject: net.http.parser: Handle full URLs in status line. --- net/http/parser.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/parser.lua b/net/http/parser.lua index c98c75af..fdcb8ebb 100644 --- a/net/http/parser.lua +++ b/net/http/parser.lua @@ -53,7 +53,6 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb) else method, path, httpversion = line:match("^(%w+) (%S+) HTTP/(1%.[01])$"); if not method then error = true; return error_cb("invalid-status-line"); end - path = path:gsub("^//+", "/"); -- TODO parse url more end end end @@ -71,6 +70,12 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb) responseheaders = headers; }; else + -- path normalization + if path:match("^https?://") then + headers.host, path = path:match("^https?://([^/]*)(.*)"); + end + path = path:gsub("^//+", "/"); -- TODO parse url more + len = len or 0; packet = { method = method; -- cgit v1.2.3 From a54e59650fb3aef98485286f3ffaf5cdf6140dab Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 26 Apr 2012 16:11:08 +0100 Subject: net.http.server: Fire http-error 400 if request fails sanity checks --- net/http/server.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index deaa44cd..938e676d 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -170,10 +170,17 @@ function handle_request(conn, request, finish_cb) }; conn._http_open_response = response; + local err; if not request.headers.host then + err = "No 'Host' header"; + elseif not request.path then + err = "Invalid path"; + end + + if err then response.status_code = 400; response.headers.content_type = "text/html"; - response:send(events.fire_event("http-error", { code = 400, message = "No 'Host' header" })); + response:send(events.fire_event("http-error", { code = 400, message = err })); else local host = request.headers.host; if host then -- cgit v1.2.3 From 887ca5f9fe8ae6730f72c2aea17aaf84ccb8a537 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 26 Apr 2012 16:25:11 +0100 Subject: Revert 98bfebb38705, moved to net.http.parser in 4fc99f1b7570 --- net/http/server.lua | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 4f9e1463..d6c3a03a 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -1,7 +1,6 @@ local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat; local parser_new = require "net.http.parser".new; -local url_parse = require "socket.url".parse; local events = require "util.events".new(); local addserver = require "net.server".addserver; local log = require "util.logger".init("http.server"); @@ -102,9 +101,6 @@ function listener.onconnect(conn) local function success_cb(request) --log("debug", "success_cb: %s", request.path); request.secure = secure; - local parsed_dest = url_parse(request.path); - request.url = parsed_dest; - request.path = parsed_dest.path; t_insert(pending, request); if not waiting then process_next(); -- cgit v1.2.3 From 7c5c2aea2ca88a0112c51c5eaf74209271d780c9 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 26 Apr 2012 16:48:16 +0100 Subject: mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit --- net/http/parser.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/parser.lua b/net/http/parser.lua index fdcb8ebb..3d9d1a87 100644 --- a/net/http/parser.lua +++ b/net/http/parser.lua @@ -2,6 +2,24 @@ local tonumber = tonumber; local assert = assert; +local function preprocess_path(path) + if path:sub(1,1) ~= "/" then + path = "/"..path; + end + local level = 0; + for component in path:gmatch("([^/]+)/") do + if component == ".." then + level = level - 1; + elseif component ~= "." then + level = level + 1; + end + if level < 0 then + return nil; + end + end + return path; +end + local httpstream = {}; function httpstream.new(success_cb, error_cb, parser_type, options_cb) @@ -74,7 +92,7 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb) if path:match("^https?://") then headers.host, path = path:match("^https?://([^/]*)(.*)"); end - path = path:gsub("^//+", "/"); -- TODO parse url more + path = preprocess_path(path); len = len or 0; packet = { -- cgit v1.2.3 From 0629f9223478422fb0d01e12bcb15e54362d5fae Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 27 Apr 2012 18:54:51 +0100 Subject: net.http.codes: Add missing 418 status code --- net/http/codes.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/http/codes.lua b/net/http/codes.lua index 2e701027..0cadd079 100644 --- a/net/http/codes.lua +++ b/net/http/codes.lua @@ -44,6 +44,7 @@ local response_codes = { [415] = "Unsupported Media Type"; [416] = "Requested Range Not Satisfiable"; [417] = "Expectation Failed"; + [418] = "I'm a teapot"; [422] = "Unprocessable Entity"; [423] = "Locked"; [424] = "Failed Dependency"; -- cgit v1.2.3 From 6cc3d15683c52470af224efe2c4d7e10bb137f81 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 27 Apr 2012 20:00:06 +0100 Subject: net.http.server: Correctly cache results of handler indexing, and also cache failures --- net/http/server.lua | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index d693fb52..00d98fcb 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -46,17 +46,20 @@ setmetatable(events._handlers, { end end end - if #handlers_array == 0 then return; end - table.sort(handlers_array, function(b, a) - local a_score, b_score = matching_handlers_set[a], matching_handlers_set[b]; - for i = 1, #a_score do - if a_score[i] ~= b_score[i] then -- If equal, compare next score value - return a_score[i] < b_score[i]; + if #handlers_array > 0 then + table.sort(handlers_array, function(b, a) + local a_score, b_score = matching_handlers_set[a], matching_handlers_set[b]; + for i = 1, #a_score do + if a_score[i] ~= b_score[i] then -- If equal, compare next score value + return a_score[i] < b_score[i]; + end end - end - return false; - end); - handlers[curr_event] = handlers_array; + return false; + end); + else + handlers_array = false; + end + rawset(handlers, curr_event, handlers_array); return handlers_array; end; __newindex = function (handlers, curr_event, handlers_array) @@ -69,6 +72,7 @@ setmetatable(events._handlers, { end end end + rawset(handlers, curr_event, handlers_array); end; }); -- cgit v1.2.3 From ecc47f29209c1d7d7e505ebf1de86355afc4937c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 27 Apr 2012 20:01:21 +0100 Subject: net.http.server: Remove unused variable --- net/http/server.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 00d98fcb..86d729f0 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -18,7 +18,6 @@ local legacy_httpserver = require "net.httpserver"; local _M = {}; local sessions = {}; -local handlers = {}; local listener = {}; -- cgit v1.2.3 From 14dcbf13d5fc2dc4ded9d51176284347bfbe8374 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 27 Apr 2012 22:37:56 +0100 Subject: net.http.server: Improve comment --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 86d729f0..978a5a82 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -64,7 +64,7 @@ setmetatable(events._handlers, { __newindex = function (handlers, curr_event, handlers_array) if handlers_array == nil and is_wildcard_event(curr_event) then - -- Invalidate all matching + -- Invalidate the indexes of all matching events for event in pairs(handlers) do if is_wildcard_match(curr_event, event) then handlers[event] = nil; -- cgit v1.2.3 From e865b1b3fe06dd681f121fd0147608f47a8bfc34 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 27 Apr 2012 23:11:23 +0100 Subject: net.http.server, mod_http: Support http_default_host config option to specify where to direct requests for unknown HTTP vhosts --- net/http/server.lua | 97 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 41 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 978a5a82..325eb42f 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -18,8 +18,9 @@ local legacy_httpserver = require "net.httpserver"; local _M = {}; local sessions = {}; - local listener = {}; +local hosts = {}; +local default_host; local function is_wildcard_event(event) return event:sub(-2, -1) == "/*"; @@ -169,54 +170,59 @@ function handle_request(conn, request, finish_cb) }; conn._http_open_response = response; - local err; - if not request.headers.host then - err = "No 'Host' header"; + local host = (request.headers.host or ""):match("[^:]+"); + + -- Some sanity checking + local err_code, err; + if not host then + err_code, err = 400, "Missing or invalid 'Host' header"; elseif not request.path then - err = "Invalid path"; + err_code, err = 400, "Invalid path"; + end + if not hosts[host] then + if hosts[default_host] then + host = default_host; + else + err_code, err = 404, "Unknown host: "..host; + end end if err then - response.status_code = 400; - response.headers.content_type = "text/html"; - response:send(events.fire_event("http-error", { code = 400, message = err })); - else - local host = request.headers.host; - if host then - host = host:match("[^:]*"):lower(); - local event = request.method.." "..host..request.path:match("[^?]*"); - local payload = { request = request, response = response }; - --log("debug", "Firing event: %s", event); - local result = events.fire_event(event, payload); - if result ~= nil then - if result ~= true then - local code, body = 200, ""; - local result_type = type(result); - if result_type == "number" then - response.status_code = result; - if result >= 400 then - body = events.fire_event("http-error", { code = result }); - end - elseif result_type == "string" then - body = result; - elseif result_type == "table" then - body = result.body; - result.body = nil; - for k, v in pairs(result) do - response[k] = v; - end - end - response:send(body); + response.status_code = err_code; + response:send(events.fire_event("http-error", { code = err_code, message = err })); + return; + end + + local event = request.method.." "..host..request.path:match("[^?]*"); + local payload = { request = request, response = response }; + --log("debug", "Firing event: %s", event); + local result = events.fire_event(event, payload); + if result ~= nil then + if result ~= true then + local code, body = 200, ""; + local result_type = type(result); + if result_type == "number" then + response.status_code = result; + if result >= 400 then + body = events.fire_event("http-error", { code = result }); + end + elseif result_type == "string" then + body = result; + elseif result_type == "table" then + body = result.body; + result.body = nil; + for k, v in pairs(result) do + response[k] = v; end - return; end + response:send(body); end - - -- if handler not called, return 404 - response.status_code = 404; - response.headers.content_type = "text/html"; - response:send(events.fire_event("http-error", { code = 404 })); + return; end + + -- if handler not called, return 404 + response.status_code = 404; + response:send(events.fire_event("http-error", { code = 404 })); end function _M.send_response(response, body) if response.finished then return; end @@ -256,6 +262,15 @@ end function _M.listen_on(port, interface, ssl) addserver(interface or "*", port, listener, "*a", ssl); end +function _M.add_host(host) + hosts[host] = true; +end +function _M.remove_host(host) + hosts[host] = nil; +end +function _M.set_default_host(host) + default_host = host; +end _M.listener = listener; _M.codes = codes; -- cgit v1.2.3 From e8746c77dad085ea37dda934eff87230796439fa Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Apr 2012 00:51:36 +0100 Subject: net.http.server: Fix traceback on missing host header (thanks darkrain) --- net/http/server.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 325eb42f..eb30da78 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -178,8 +178,7 @@ function handle_request(conn, request, finish_cb) err_code, err = 400, "Missing or invalid 'Host' header"; elseif not request.path then err_code, err = 400, "Invalid path"; - end - if not hosts[host] then + elseif not hosts[host] then if hosts[default_host] then host = default_host; else -- cgit v1.2.3 From 7f6dcc373f924b1a0a7dfa6739aa22545215c9db Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Apr 2012 01:13:49 +0100 Subject: net.http.server: Try default_host if client sent no host anywhere, otherwise... fail. It's 2012. --- net/http/server.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index eb30da78..8b91b4d3 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -174,15 +174,15 @@ function handle_request(conn, request, finish_cb) -- Some sanity checking local err_code, err; - if not host then - err_code, err = 400, "Missing or invalid 'Host' header"; - elseif not request.path then + if not request.path then err_code, err = 400, "Invalid path"; elseif not hosts[host] then if hosts[default_host] then host = default_host; - else + elseif host then err_code, err = 404, "Unknown host: "..host; + else + err_code, err = 400, "Missing or invalid 'Host' header"; end end -- cgit v1.2.3 From 2d24f6f5cb71423832226b47d64fafb4af40d2d5 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Apr 2012 14:13:51 +0100 Subject: net.httpserver, net.httpserver_listener: Remove (obsoleted by net.http.* and mod_http, see http://prosody.im/doc/developers/http ) --- net/httpserver.lua | 238 -------------------------------------------- net/httpserver_listener.lua | 46 --------- 2 files changed, 284 deletions(-) delete mode 100644 net/httpserver.lua delete mode 100644 net/httpserver_listener.lua (limited to 'net') diff --git a/net/httpserver.lua b/net/httpserver.lua deleted file mode 100644 index 0f5a4186..00000000 --- a/net/httpserver.lua +++ /dev/null @@ -1,238 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - - -local url_parse = require "socket.url".parse; -local httpstream_new = require "util.httpstream".new; - ---local connlisteners_start = require "net.connlisteners".start; ---local connlisteners_get = require "net.connlisteners".get; -local listener; - -local t_insert, t_concat = table.insert, table.concat; -local tonumber, tostring, pairs, ipairs, type = tonumber, tostring, pairs, ipairs, type; -local xpcall = xpcall; -local debug_traceback = debug.traceback; - -local urlencode = function (s) return s and (s:gsub("%W", function (c) return ("%%%02x"):format(c:byte()); end)); end - -local log = require "util.logger".init("httpserver"); - -local http_servers = {}; - -module "httpserver" - -local default_handler; - -local function send_response(request, response) - -- Write status line - local resp; - if response.body or response.headers then - local body = response.body and tostring(response.body); - log("debug", "Sending response to %s", request.id); - resp = { "HTTP/1.0 "..(response.status or "200 OK").."\r\n" }; - local h = response.headers; - if h then - for k, v in pairs(h) do - t_insert(resp, k..": "..v.."\r\n"); - end - end - if body and not (h and h["Content-Length"]) then - t_insert(resp, "Content-Length: "..#body.."\r\n"); - end - t_insert(resp, "\r\n"); - - if body and request.method ~= "HEAD" then - t_insert(resp, body); - end - request.write(t_concat(resp)); - else - -- Response we have is just a string (the body) - log("debug", "Sending 200 response to %s", request.id or ""); - - local resp = "HTTP/1.0 200 OK\r\n" - .. "Connection: close\r\n" - .. "Content-Type: text/html\r\n" - .. "Content-Length: "..#response.."\r\n" - .. "\r\n" - .. response; - - request.write(resp); - end - if not request.stayopen then - request:destroy(); - end -end - -local function call_callback(request, err) - if request.handled then return; end - request.handled = true; - local callback = request.callback; - if not callback and request.path then - local path = request.url.path; - local base = path:match("^/([^/?]+)"); - if not base then - base = path:match("^http://[^/?]+/([^/?]+)"); - end - - callback = (request.server and request.server.handlers[base]) or default_handler; - end - if callback then - local _callback = callback; - function callback(method, body, request) - local ok, result = xpcall(function() return _callback(method, body, request) end, debug_traceback); - if ok then return result; end - log("error", "Error in HTTP server handler: %s", result); - -- TODO: When we support pipelining, request.destroyed - -- won't be the right flag - we just want to see if there - -- has been a response to this request yet. - if not request.destroyed then - return { - status = "500 Internal Server Error"; - headers = { ["Content-Type"] = "text/plain" }; - body = "There was an error processing your request. See the error log for more details."; - }; - end - end - if err then - log("debug", "Request error: "..err); - if not callback(nil, err, request) then - destroy_request(request); - end - return; - end - - local response = callback(request.method, request.body and t_concat(request.body), request); - if response then - if response == true and not request.destroyed then - -- Keep connection open, we will reply later - log("debug", "Request %s left open, on_destroy is %s", request.id, tostring(request.on_destroy)); - elseif response ~= true then - -- Assume response - send_response(request, response); - destroy_request(request); - end - else - log("debug", "Request handler provided no response, destroying request..."); - -- No response, close connection - destroy_request(request); - end - end -end - -local function request_reader(request, data, startpos) - if not request.parser then - local function success_cb(r) - for k,v in pairs(r) do request[k] = v; end - request.url = url_parse(request.path); - request.url.path = request.url.path and request.url.path:gsub("%%(%x%x)", function(x) return x.char(tonumber(x, 16)) end); - request.body = { request.body }; - call_callback(request); - end - local function error_cb(r) - call_callback(request, r or "connection-closed"); - destroy_request(request); - end - request.parser = httpstream_new(success_cb, error_cb); - end - request.parser:feed(data); -end - --- The default handler for requests -default_handler = function (method, body, request) - log("debug", method.." request for "..tostring(request.path) .. " on port "..request.handler:serverport()); - return { status = "404 Not Found", - headers = { ["Content-Type"] = "text/html" }, - body = "Page Not FoundNot here :(" }; -end - - -function new_request(handler) - return { handler = handler, conn = handler, - write = function (...) return handler:write(...); end, state = "request", - server = http_servers[handler:serverport()], - send = send_response, - destroy = destroy_request, - id = tostring{}:match("%x+$") - }; -end - -function destroy_request(request) - log("debug", "Destroying request %s", request.id); - --listener = listener or connlisteners_get("httpserver"); - if not request.destroyed then - request.destroyed = true; - if request.on_destroy then - log("debug", "Request has destroy callback"); - request.on_destroy(request); - else - log("debug", "Request has no destroy callback"); - end - request.handler:close() - if request.conn then - listener.ondisconnect(request.conn, "closed"); - end - end -end - -function new(params) - local http_server = http_servers[params.port]; - if not http_server then - http_server = { handlers = {} }; - http_servers[params.port] = http_server; - -- We weren't already listening on this port, so start now - --connlisteners_start("httpserver", params); - end - if params.base then - http_server.handlers[params.base] = params.handler; - end -end - -function set_default_handler(handler) - default_handler = handler; -end - -function new_from_config(ports, handle_request, default_options) - if type(handle_request) == "string" then -- COMPAT with old plugins - log("warn", "Old syntax of httpserver.new_from_config being used to register %s", handle_request); - handle_request, default_options = default_options, { base = handle_request }; - end - ports = ports or {5280}; - for _, options in ipairs(ports) do - local port = default_options.port or 5280; - local base = default_options.base; - local ssl = default_options.ssl or false; - local interface = default_options.interface; - if type(options) == "number" then - port = options; - elseif type(options) == "table" then - port = options.port or port; - base = options.path or base; - ssl = options.ssl or ssl; - interface = options.interface or interface; - elseif type(options) == "string" then - base = options; - end - - if ssl then - ssl.mode = "server"; - ssl.protocol = "sslv23"; - ssl.options = "no_sslv2"; - end - - new{ port = port, interface = interface, - base = base, handler = handle_request, - ssl = ssl, type = (ssl and "ssl") or "tcp" }; - end -end - -_M.request_reader = request_reader; -_M.send_response = send_response; -_M.urlencode = urlencode; - -return _M; diff --git a/net/httpserver_listener.lua b/net/httpserver_listener.lua deleted file mode 100644 index dd14b43c..00000000 --- a/net/httpserver_listener.lua +++ /dev/null @@ -1,46 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - - - -local connlisteners_register = require "net.connlisteners".register; -local new_request = require "net.httpserver".new_request; -local request_reader = require "net.httpserver".request_reader; - -local requests = {}; -- Open requests - -local httpserver = { default_port = 80, default_mode = "*a" }; - -function httpserver.onincoming(conn, data) - local request = requests[conn]; - - if not request then - request = new_request(conn); - requests[conn] = request; - - -- If using HTTPS, request is secure - if conn:ssl() then - request.secure = true; - end - end - - if data and data ~= "" then - request_reader(request, data); - end -end - -function httpserver.ondisconnect(conn, err) - local request = requests[conn]; - if request and not request.destroyed then - request.conn = nil; - request_reader(request, nil); - end - requests[conn] = nil; -end - -connlisteners_register("httpserver", httpserver); -- cgit v1.2.3 From 622996868508974eef027f5ea0540e32b2f883e6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Apr 2012 14:27:48 +0100 Subject: net.http.server: Remove unused imports and variables (fixes traceback due to removed net.httpserver) --- net/http/server.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 8b91b4d3..295592d3 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -12,8 +12,6 @@ local xpcall = xpcall; local debug = debug; local tostring = tostring; local codes = require "net.http.codes"; -local _G = _G; -local legacy_httpserver = require "net.httpserver"; local _M = {}; @@ -90,7 +88,7 @@ function listener.onconnect(conn) local secure = conn:ssl() and true or nil; local pending = {}; local waiting = false; - local function process_next(last_response) + local function process_next() --if waiting then log("debug", "can't process_next, waiting"); return; end if sessions[conn] and #pending > 0 then local request = t_remove(pending); @@ -198,7 +196,7 @@ function handle_request(conn, request, finish_cb) local result = events.fire_event(event, payload); if result ~= nil then if result ~= true then - local code, body = 200, ""; + local body = ""; local result_type = type(result); if result_type == "number" then response.status_code = result; -- cgit v1.2.3 From 30957d900de03520b693e9ee5d0310916e5600b4 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Apr 2012 16:41:35 +0100 Subject: net.httpserver: Add compatibility stub --- net/httpserver.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 net/httpserver.lua (limited to 'net') diff --git a/net/httpserver.lua b/net/httpserver.lua new file mode 100644 index 00000000..7d574788 --- /dev/null +++ b/net/httpserver.lua @@ -0,0 +1,15 @@ +-- COMPAT w/pre-0.9 +local log = require "util.logger".init("net.httpserver"); +local traceback = debug.traceback; + +module "httpserver" + +function fail() + log("error", "Attempt to use legacy HTTP API. For more info see http://prosody.im/doc/developers/legacy_http"); + log("error", "Legacy HTTP API usage, %s", traceback("", 2)); +end + +new, new_from_config = fail, fail; +set_default_handler = fail; + +return _M; -- cgit v1.2.3 From cc6bcc5877af74cabd0bb30122973a6ca5d19ae4 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Apr 2012 19:36:09 +0100 Subject: net.http.server: Use response.body if it exists and body is not specified to send_response --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 295592d3..e15e6e14 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -228,7 +228,7 @@ function _M.send_response(response, body) local status_line = "HTTP/"..response.request.httpversion.." "..(response.status or codes[response.status_code]); local headers = response.headers; - body = body or ""; + body = body or response.body or ""; headers.content_length = #body; local output = { status_line }; -- cgit v1.2.3 From d4578e06775bd9bdb6bef6eaf9b5d1516bc77767 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Apr 2012 19:36:57 +0100 Subject: net.http.server: Code cleanup/adjustment now that send_response() accepts response.body --- net/http/server.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index e15e6e14..69908e4e 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -196,7 +196,7 @@ function handle_request(conn, request, finish_cb) local result = events.fire_event(event, payload); if result ~= nil then if result ~= true then - local body = ""; + local body; local result_type = type(result); if result_type == "number" then response.status_code = result; @@ -206,8 +206,6 @@ function handle_request(conn, request, finish_cb) elseif result_type == "string" then body = result; elseif result_type == "table" then - body = result.body; - result.body = nil; for k, v in pairs(result) do response[k] = v; end -- cgit v1.2.3 From a2055895d362fed58ff314820bb7fddd53e40436 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Apr 2012 23:13:49 +0100 Subject: net.connlisteners: Add COMPAT stub, use portmanager! --- net/connlisteners.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 net/connlisteners.lua (limited to 'net') diff --git a/net/connlisteners.lua b/net/connlisteners.lua new file mode 100644 index 00000000..99ddc720 --- /dev/null +++ b/net/connlisteners.lua @@ -0,0 +1,15 @@ +-- COMPAT w/pre-0.9 +local log = require "util.logger".init("net.connlisteners"); +local traceback = debug.traceback; + +module "httpserver" + +function fail() + log("error", "Attempt to use legacy connlisteners API. For more info see http://prosody.im/doc/developers/network"); + log("error", "Legacy connlisteners API usage, %s", traceback("", 2)); +end + +register, deregister = fail, fail; +get, start = fail, fail, epic_fail; + +return _M; -- cgit v1.2.3