aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/except.c23
-rw-r--r--src/ftp.lua16
-rw-r--r--src/http.lua23
-rw-r--r--src/smtp.lua7
-rw-r--r--src/socket.lua2
-rw-r--r--src/tp.lua49
6 files changed, 57 insertions, 63 deletions
diff --git a/src/except.c b/src/except.c
index 53a65ac..68abf70 100644
--- a/src/except.c
+++ b/src/except.c
@@ -12,33 +12,21 @@
12/*=========================================================================*\ 12/*=========================================================================*\
13* Internal function prototypes. 13* Internal function prototypes.
14\*=========================================================================*/ 14\*=========================================================================*/
15static int global_try(lua_State *L);
16static int global_protect(lua_State *L); 15static int global_protect(lua_State *L);
17static int global_newtry(lua_State *L); 16static int global_newtry(lua_State *L);
18static int protected(lua_State *L); 17static int protected(lua_State *L);
19static int finalize(lua_State *L); 18static int finalize(lua_State *L);
19static int do_nothing(lua_State *L);
20 20
21/* except functions */ 21/* except functions */
22static luaL_reg func[] = { 22static luaL_reg func[] = {
23 {"try", global_try},
24 {"newtry", global_newtry}, 23 {"newtry", global_newtry},
25 {"protect", global_protect}, 24 {"protect", global_protect},
26 {NULL, NULL} 25 {NULL, NULL}
27}; 26};
28 27
29/*-------------------------------------------------------------------------*\ 28/*-------------------------------------------------------------------------*\
30* Try method 29* Try factory
31\*-------------------------------------------------------------------------*/
32static int global_try(lua_State *L) {
33 if (lua_isnil(L, 1) || (lua_isboolean(L, 1) && !lua_toboolean(L, 1))) {
34 lua_settop(L, 2);
35 lua_error(L);
36 return 0;
37 } else return lua_gettop(L);
38}
39
40/*-------------------------------------------------------------------------*\
41* Finalizer factory
42\*-------------------------------------------------------------------------*/ 30\*-------------------------------------------------------------------------*/
43static int finalize(lua_State *L) { 31static int finalize(lua_State *L) {
44 if (lua_isnil(L, 1) || (lua_isboolean(L, 1) && !lua_toboolean(L, 1))) { 32 if (lua_isnil(L, 1) || (lua_isboolean(L, 1) && !lua_toboolean(L, 1))) {
@@ -50,7 +38,14 @@ static int finalize(lua_State *L) {
50 } else return lua_gettop(L); 38 } else return lua_gettop(L);
51} 39}
52 40
41static int do_nothing(lua_State *L) {
42 (void) L;
43 return 0;
44}
45
53static int global_newtry(lua_State *L) { 46static int global_newtry(lua_State *L) {
47 lua_settop(L, 1);
48 if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
54 lua_pushcclosure(L, finalize, 1); 49 lua_pushcclosure(L, finalize, 1);
55 return 1; 50 return 1;
56} 51}
diff --git a/src/ftp.lua b/src/ftp.lua
index ad02c72..1c7ea71 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -32,14 +32,10 @@ local metat = { __index = {} }
32 32
33function open(server, port) 33function open(server, port)
34 local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT)) 34 local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT))
35 local f = { tp = tp } 35 local f = setmetat({ tp = tp }, metat)
36 -- make sure everything gets closed in an exception 36 -- make sure everything gets closed in an exception
37 f.try = socket.newtry(function() 37 f.try = socket.newtry(function() f:close() end)
38 tp:close() 38 return f
39 if f.data then f.data:close() end
40 if f.server then f.server:close() end
41 end)
42 return setmetatable(f, metat)
43end 39end
44 40
45function metat.__index:portconnect() 41function metat.__index:portconnect()
@@ -173,13 +169,9 @@ function metat.__index:quit()
173end 169end
174 170
175function metat.__index:close() 171function metat.__index:close()
176 self.tp:close()
177 if self.data then self.data:close() end 172 if self.data then self.data:close() end
178 if self.server then self.server:close() end 173 if self.server then self.server:close() end
179 self.tp = nil 174 return self.tp:close()
180 self.data = nil
181 self.server = nil
182 return 1
183end 175end
184 176
185----------------------------------------------------------------------------- 177-----------------------------------------------------------------------------
diff --git a/src/http.lua b/src/http.lua
index d8889e1..9c568bc 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -32,11 +32,12 @@ local metat = { __index = {} }
32 32
33function open(host, port) 33function open(host, port)
34 local c = socket.try(socket.tcp()) 34 local c = socket.try(socket.tcp())
35 local h = setmetatable({ c = c }, metat)
35 -- make sure the connection gets closed on exception 36 -- make sure the connection gets closed on exception
36 local try = socket.newtry(function() c:close() end) 37 h.try = socket.newtry(function() h:close() end)
37 try(c:settimeout(TIMEOUT)) 38 h.try(c:settimeout(TIMEOUT))
38 try(c:connect(host, port or PORT)) 39 h.try(c:connect(host, port or PORT))
39 return setmetatable({ c = c, try = try }, metat) 40 return h
40end 41end
41 42
42function metat.__index:sendrequestline(method, uri) 43function metat.__index:sendrequestline(method, uri)
@@ -57,9 +58,8 @@ function metat.__index:sendbody(headers, source, step)
57 source = source or ltn12.source.empty() 58 source = source or ltn12.source.empty()
58 step = step or ltn12.pump.step 59 step = step or ltn12.pump.step
59 -- if we don't know the size in advance, send chunked and hope for the best 60 -- if we don't know the size in advance, send chunked and hope for the best
60 local mode 61 local mode = "http-chunked"
61 if headers["content-length"] then mode = "keep-open" 62 if headers["content-length"] then mode = "keep-open" end
62 else mode = "http-chunked" end
63 return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) 63 return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
64end 64end
65 65
@@ -99,10 +99,9 @@ function metat.__index:receivebody(headers, sink, step)
99 step = step or ltn12.pump.step 99 step = step or ltn12.pump.step
100 local length = tonumber(headers["content-length"]) 100 local length = tonumber(headers["content-length"])
101 local TE = headers["transfer-encoding"] 101 local TE = headers["transfer-encoding"]
102 local mode 102 local mode = "default" -- connection close
103 if TE and TE ~= "identity" then mode = "http-chunked" 103 if TE and TE ~= "identity" then mode = "http-chunked"
104 elseif tonumber(headers["content-length"]) then mode = "by-length" 104 elseif tonumber(headers["content-length"]) then mode = "by-length" end
105 else mode = "default" end
106 return self.try(ltn12.pump.all(socket.source(mode, self.c, length), 105 return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
107 sink, step)) 106 sink, step))
108end 107end
@@ -191,9 +190,9 @@ function tauthorize(reqt)
191end 190end
192 191
193function tredirect(reqt, headers) 192function tredirect(reqt, headers)
194 -- the RFC says the redirect URL has to be absolute, but some
195 -- servers do not respect that
196 return trequest { 193 return trequest {
194 -- the RFC says the redirect URL has to be absolute, but some
195 -- servers do not respect that
197 url = url.absolute(reqt, headers["location"]), 196 url = url.absolute(reqt, headers["location"]),
198 source = reqt.source, 197 source = reqt.source,
199 sink = reqt.sink, 198 sink = reqt.sink,
diff --git a/src/smtp.lua b/src/smtp.lua
index d6357d2..70b511c 100644
--- a/src/smtp.lua
+++ b/src/smtp.lua
@@ -60,7 +60,7 @@ function metat.__index:quit()
60end 60end
61 61
62function metat.__index:close() 62function metat.__index:close()
63 return self.try(self.tp:close()) 63 return self.tp:close()
64end 64end
65 65
66function metat.__index:login(user, password) 66function metat.__index:login(user, password)
@@ -104,9 +104,10 @@ end
104 104
105function open(server, port) 105function open(server, port)
106 local tp = socket.try(tp.connect(server or SERVER, port or PORT, TIMEOUT)) 106 local tp = socket.try(tp.connect(server or SERVER, port or PORT, TIMEOUT))
107 local s = setmetatable({tp = tp}, metat)
107 -- make sure tp is closed if we get an exception 108 -- make sure tp is closed if we get an exception
108 local try = socket.newtry(function() tp:close() end) 109 local try = socket.newtry(function() s:close() end)
109 return setmetatable({ tp = tp, try = try}, metat) 110 return s
110end 111end
111 112
112--------------------------------------------------------------------------- 113---------------------------------------------------------------------------
diff --git a/src/socket.lua b/src/socket.lua
index 0a681bf..4d64651 100644
--- a/src/socket.lua
+++ b/src/socket.lua
@@ -37,6 +37,8 @@ function socket.bind(host, port, backlog)
37 return sock 37 return sock
38end 38end
39 39
40socket.try = socket.newtry()
41
40function socket.choose(table) 42function socket.choose(table)
41 return function(name, opt1, opt2) 43 return function(name, opt1, opt2)
42 if type(name) ~= "string" then 44 if type(name) ~= "string" then
diff --git a/src/tp.lua b/src/tp.lua
index 7b581b9..153541a 100644
--- a/src/tp.lua
+++ b/src/tp.lua
@@ -20,16 +20,16 @@ TIMEOUT = 60
20-- Implementation 20-- Implementation
21----------------------------------------------------------------------------- 21-----------------------------------------------------------------------------
22-- gets server reply (works for SMTP and FTP) 22-- gets server reply (works for SMTP and FTP)
23local function get_reply(control) 23local function get_reply(c)
24 local code, current, sep 24 local code, current, sep
25 local line, err = control:receive() 25 local line, err = c:receive()
26 local reply = line 26 local reply = line
27 if err then return nil, err end 27 if err then return nil, err end
28 code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) 28 code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
29 if not code then return nil, "invalid server reply" end 29 if not code then return nil, "invalid server reply" end
30 if sep == "-" then -- reply is multiline 30 if sep == "-" then -- reply is multiline
31 repeat 31 repeat
32 line, err = control:receive() 32 line, err = c:receive()
33 if err then return nil, err end 33 if err then return nil, err end
34 current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) 34 current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
35 reply = reply .. "\n" .. line 35 reply = reply .. "\n" .. line
@@ -43,7 +43,7 @@ end
43local metat = { __index = {} } 43local metat = { __index = {} }
44 44
45function metat.__index:check(ok) 45function metat.__index:check(ok)
46 local code, reply = get_reply(self.control) 46 local code, reply = get_reply(self.c)
47 if not code then return nil, reply end 47 if not code then return nil, reply end
48 if type(ok) ~= "function" then 48 if type(ok) ~= "function" then
49 if type(ok) == "table" then 49 if type(ok) == "table" then
@@ -59,50 +59,55 @@ function metat.__index:check(ok)
59end 59end
60 60
61function metat.__index:command(cmd, arg) 61function metat.__index:command(cmd, arg)
62 if arg then return self.control:send(cmd .. " " .. arg.. "\r\n") 62 if arg then return self.c:send(cmd .. " " .. arg.. "\r\n")
63 else return self.control:send(cmd .. "\r\n") end 63 else return self.c:send(cmd .. "\r\n") end
64end 64end
65 65
66function metat.__index:sink(snk, pat) 66function metat.__index:sink(snk, pat)
67 local chunk, err = control:receive(pat) 67 local chunk, err = c:receive(pat)
68 return snk(chunk, err) 68 return snk(chunk, err)
69end 69end
70 70
71function metat.__index:send(data) 71function metat.__index:send(data)
72 return self.control:send(data) 72 return self.c:send(data)
73end 73end
74 74
75function metat.__index:receive(pat) 75function metat.__index:receive(pat)
76 return self.control:receive(pat) 76 return self.c:receive(pat)
77end 77end
78 78
79function metat.__index:getfd() 79function metat.__index:getfd()
80 return self.control:getfd() 80 return self.c:getfd()
81end 81end
82 82
83function metat.__index:dirty() 83function metat.__index:dirty()
84 return self.control:dirty() 84 return self.c:dirty()
85end 85end
86 86
87function metat.__index:getcontrol() 87function metat.__index:getcontrol()
88 return self.control 88 return self.c
89end 89end
90 90
91function metat.__index:source(source, step) 91function metat.__index:source(source, step)
92 local sink = socket.sink("keep-open", self.control) 92 local sink = socket.sink("keep-open", self.c)
93 return ltn12.pump.all(source, sink, step or ltn12.pump.step) 93 return ltn12.pump.all(source, sink, step or ltn12.pump.step)
94end 94end
95 95
96-- closes the underlying control 96-- closes the underlying c
97function metat.__index:close() 97function metat.__index:close()
98 self.control:close() 98 self.c:close()
99 return 1 99 return 1
100end 100end
101 101
102-- connect with server and return control object 102-- connect with server and return c object
103connect = socket.protect(function(host, port, timeout) 103function connect(host, port, timeout)
104 local control = socket.try(socket.tcp()) 104 local c, e = socket.tcp()
105 socket.try(control:settimeout(timeout or TIMEOUT)) 105 if not c then return nil, e end
106 socket.try(control:connect(host, port)) 106 c:settimeout(timeout or TIMEOUT)
107 return setmetatable({control = control}, metat) 107 local r, e = c:connect(host, port)
108end) 108 if not r then
109 c:close()
110 return nil, e
111 end
112 return setmetatable({c = c}, metat)
113end