diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/connlisteners.lua | 5 | ||||
-rw-r--r-- | net/dns.lua | 24 | ||||
-rw-r--r-- | net/http.lua | 172 | ||||
-rw-r--r-- | net/httpclient_listener.lua | 36 | ||||
-rw-r--r-- | net/server.lua | 3 | ||||
-rw-r--r-- | net/xmppclient_listener.lua | 6 | ||||
-rw-r--r-- | net/xmppserver_listener.lua | 6 |
7 files changed, 223 insertions, 29 deletions
diff --git a/net/connlisteners.lua b/net/connlisteners.lua index 9be144da..f027dfeb 100644 --- a/net/connlisteners.lua +++ b/net/connlisteners.lua @@ -1,4 +1,4 @@ --- Prosody IM v0.1 +-- Prosody IM v0.2 -- Copyright (C) 2008 Matthew Wild -- Copyright (C) 2008 Waqas Hussain -- @@ -47,7 +47,8 @@ end function get(name) local h = listeners[name]; if not h then - pcall(dofile, listeners_dir..name:gsub("[^%w%-]", "_").."_listener.lua"); + local ok, ret = pcall(dofile, listeners_dir..name:gsub("[^%w%-]", "_").."_listener.lua"); + if not ok then return nil, ret; end h = listeners[name]; end return h; diff --git a/net/dns.lua b/net/dns.lua index 8cf092fb..faad2b93 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -1,24 +1,6 @@ --- Prosody IM v0.1 --- Copyright (C) 2008 Matthew Wild --- Copyright (C) 2008 Waqas Hussain --- --- This program is free software; you can redistribute it and/or --- modify it under the terms of the GNU General Public License --- as published by the Free Software Foundation; either version 2 --- of the License, or (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program; if not, write to the Free Software --- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- - - - +-- Prosody IM v0.2 +-- This file is included with Prosody IM. It has modifications, +-- which are hereby placed in the public domain. -- public domain 20080404 lua@ztact.com diff --git a/net/http.lua b/net/http.lua new file mode 100644 index 00000000..e8a981b8 --- /dev/null +++ b/net/http.lua @@ -0,0 +1,172 @@ + +local socket = require "socket" +local mime = require "mime" +local url = require "socket.url" + +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 tonumber, tostring, pairs = tonumber, tostring, pairs; +local print = function () end + +local urlcodes = setmetatable({}, { __index = function (t, k) t[k] = char(tonumber("0x"..k)); return t[k]; end }); +local urlencode = function (s) return s and (s:gsub("%W", function (c) return string.format("%%%x", c:byte()); end)); end + +module "http" + +local function expectbody(reqt, code) + if reqt.method == "HEAD" then return nil end + if code == 204 or code == 304 then return nil end + if code >= 100 and code < 200 then return nil end + return 1 +end + +local function request_reader(request, data, startpos) + if not data then + if request.body then + request.callback(request.code, t_concat(request.body), request); + else + -- Error.. connection was closed prematurely + request.callback(0, "connection-closed", request); + end + destroy_request(request); + return; + end + if request.state == "body" then + print("Reading body...") + if not request.body then request.body = {}; request.havebodylength, request.bodylength = 0, tonumber(request.responseheaders["content-length"]); end + if startpos then + data = data:sub(startpos, -1) + end + t_insert(request.body, data); + if request.bodylength then + request.havebodylength = request.havebodylength + #data; + if request.havebodylength >= request.bodylength then + -- We have the body + if request.callback then + request.callback(request.code, t_concat(request.body), request); + end + end + print("", "Have "..request.havebodylength.." bytes out of "..request.bodylength); + end + elseif request.state == "headers" then + print("Reading headers...") + local pos = startpos; + local headers = request.responseheaders or {}; + for line in data:sub(startpos, -1):gmatch("(.-)\r\n") do + startpos = startpos + #line + 2; + local k, v = line:match("(%S+): (.+)"); + if k and v then + headers[k:lower()] = v; + print("Header: "..k:lower().." = "..v); + elseif #line == 0 then + request.responseheaders = headers; + break; + else + print("Unhandled header line: "..line); + end + end + -- Reached the end of the headers + request.state = "body"; + if #data > startpos then + return request_reader(request, data, startpos); + end + elseif request.state == "status" then + print("Reading status...") + local http, code, text, linelen = data:match("^HTTP/(%S+) (%d+) (.-)\r\n()", startpos); + if not code then + return request.callback(0, "invalid-status-line", request); + end + + request.responsecode, request.responseversion = code, http; + + if request.onlystatus or not expectbody(request, tonumber(code)) then + if request.callback then + request.callback(code, nil, request); + end + destroy_request(request); + return; + end + + request.state = "headers"; + + if #data > linelen then + return request_reader(request, data, linelen); + end + end +end + +function request(u, callback, ex) + local req = url.parse(u); + + local custom_headers, body; + local default_headers = { ["Host"] = req.host, ["User-Agent"] = "Prosody XMPP Server" } + + + if req.userinfo then + default_headers["Authorization"] = "Basic "..mime.b64(req.userinfo); + end + + if ex then + custom_headers = ex.custom_headers; + req.onlystatus = ex.onlystatus; + body = ex.body; + if body then + req.method = "POST "; + default_headers["Content-Length"] = tostring(#body); + default_headers["Content-Type"] = "application/x-www-form-urlencoded"; + end + if ex.method then req.method = ex.method; end + end + + req.handler, req.conn = server.wraptcpclient(listener, socket.tcp(), req.host, req.port or 80, 0, "*a"); + req.write = req.handler.write; + req.conn:settimeout(0); + local ok, err = req.conn:connect(req.host, req.port or 80); + if not ok and err ~= "timeout" then + return nil, err; + end + + req.write((req.method or "GET ")..req.path.." HTTP/1.0\r\n"); + local t = { [2] = ": ", [4] = "\r\n" }; + if custom_headers then + for k, v in pairs(custom_headers) do + t[1], t[3] = k, v; + req.write(t_concat(t)); + default_headers[k] = nil; + end + end + + for k, v in pairs(default_headers) do + t[1], t[3] = k, v; + req.write(t_concat(t)); + default_headers[k] = nil; + end + req.write("\r\n"); + + if body then + req.write(body); + end + + req.callback = callback; + req.reader = request_reader; + req.state = "status" + + listener.register_request(req.handler, req); + + return req; +end + +function destroy_request(request) + if request.conn then + request.handler.close() + listener.disconnect(request.conn, "closed"); + end +end + +_M.urlencode = urlencode; + +return _M; diff --git a/net/httpclient_listener.lua b/net/httpclient_listener.lua new file mode 100644 index 00000000..1948f278 --- /dev/null +++ b/net/httpclient_listener.lua @@ -0,0 +1,36 @@ + +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.listener(conn, data) + local request = requests[conn]; + + if not request then + print("NO REQUEST!! for "..tostring(conn)); + return; + end + + if data and request.reader then + request:reader(data); + end +end + +function httpclient.disconnect(conn, err) + local request = requests[conn]; + if request then + request:reader(nil); + end + --requests[conn] = nil; +end + +function httpclient.register_request(conn, req) + print("Registering a request for "..tostring(conn)); + requests[conn] = req; +end + +connlisteners_register("httpclient", httpclient); diff --git a/net/server.lua b/net/server.lua index 5c129753..4e5ec366 100644 --- a/net/server.lua +++ b/net/server.lua @@ -587,6 +587,8 @@ wraptcpclient = function( listener, socket, ip, serverport, clientport, mode ) local eol, fatal_send_error + socket:settimeout(0); + local rstat, sstat = 0, 0 --// local import of socket methods //-- @@ -833,5 +835,6 @@ return { stats = stats, closeall = closeall, addtimer = addtimer, + wraptcpclient = wraptcpclient, wraptlsclient = wraptlsclient, } diff --git a/net/xmppclient_listener.lua b/net/xmppclient_listener.lua index a130a0c1..357516e9 100644 --- a/net/xmppclient_listener.lua +++ b/net/xmppclient_listener.lua @@ -1,4 +1,4 @@ --- Prosody IM v0.1 +-- Prosody IM v0.2 -- Copyright (C) 2008 Matthew Wild -- Copyright (C) 2008 Waqas Hussain -- @@ -36,7 +36,7 @@ local sm_streamopened = sessionmanager.streamopened; local sm_streamclosed = sessionmanager.streamclosed; local st = stanza; -local stream_callbacks = { ns = "http://etherx.jabber.org/streams", streamopened = sm_streamopened, streamclosed = sm_streamclosed, handlestanza = core_process_stanza }; +local stream_callbacks = { stream_tag = "http://etherx.jabber.org/streams|stream", streamopened = sm_streamopened, streamclosed = sm_streamclosed, handlestanza = core_process_stanza }; function stream_callbacks.error(session, error, data) if error == "no-stream" then @@ -47,7 +47,7 @@ function stream_callbacks.error(session, error, data) end end -local function handleerr(err) log("error", "Traceback[c2s]:", err, debug.traceback()); end +local function handleerr(err) log("error", "Traceback[c2s]: %s: %s", tostring(err), debug.traceback()); end function stream_callbacks.handlestanza(a, b) xpcall(function () core_process_stanza(a, b) end, handleerr); end diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua index b8198beb..36b4c476 100644 --- a/net/xmppserver_listener.lua +++ b/net/xmppserver_listener.lua @@ -1,4 +1,4 @@ --- Prosody IM v0.1 +-- Prosody IM v0.2 -- Copyright (C) 2008 Matthew Wild -- Copyright (C) 2008 Waqas Hussain -- @@ -28,7 +28,7 @@ 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 = { ns = "http://etherx.jabber.org/streams", streamopened = s2s_streamopened, streamclosed = s2s_streamclosed, handlestanza = core_process_stanza }; +local stream_callbacks = { stream_tag = "http://etherx.jabber.org/streams|stream", streamopened = s2s_streamopened, streamclosed = s2s_streamclosed, handlestanza = core_process_stanza }; function stream_callbacks.error(session, error, data) if error == "no-stream" then @@ -39,7 +39,7 @@ function stream_callbacks.error(session, error, data) end end -local function handleerr(err) log("error", "Traceback[s2s]:", err, debug.traceback()); end +local function handleerr(err) log("error", "Traceback[s2s]: %s: %s", tostring(err), debug.traceback()); end function stream_callbacks.handlestanza(a, b) xpcall(function () core_process_stanza(a, b) end, handleerr); end |