aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/auxiliar.c50
-rw-r--r--src/auxiliar.h25
-rw-r--r--src/buffer.c9
-rw-r--r--src/except.c52
-rw-r--r--src/except.h35
-rw-r--r--src/ftp.lua73
-rw-r--r--src/http.lua351
-rw-r--r--src/inet.c1
-rw-r--r--src/ltn12.lua21
-rw-r--r--src/luasocket.c71
-rw-r--r--src/luasocket.h1
-rw-r--r--src/mime.c12
-rw-r--r--src/mime.h1
-rw-r--r--src/mime.lua14
-rw-r--r--src/select.c221
-rw-r--r--src/smtp.lua50
-rw-r--r--src/socket.lua13
-rw-r--r--src/tcp.c5
-rw-r--r--src/timeout.c8
-rw-r--r--src/tp.lua26
-rw-r--r--src/udp.c5
-rw-r--r--src/url.lua4
22 files changed, 621 insertions, 427 deletions
diff --git a/src/auxiliar.c b/src/auxiliar.c
index b1f9203..9a37e10 100644
--- a/src/auxiliar.c
+++ b/src/auxiliar.c
@@ -7,7 +7,6 @@
7#include <string.h> 7#include <string.h>
8#include <stdio.h> 8#include <stdio.h>
9 9
10#include "luasocket.h"
11#include "auxiliar.h" 10#include "auxiliar.h"
12 11
13/*=========================================================================*\ 12/*=========================================================================*\
@@ -16,16 +15,15 @@
16/*-------------------------------------------------------------------------*\ 15/*-------------------------------------------------------------------------*\
17* Initializes the module 16* Initializes the module
18\*-------------------------------------------------------------------------*/ 17\*-------------------------------------------------------------------------*/
19int aux_open(lua_State *L) 18int aux_open(lua_State *L) {
20{
21 return 0; 19 return 0;
22} 20}
23 21
24/*-------------------------------------------------------------------------*\ 22/*-------------------------------------------------------------------------*\
25* Creates a new class with given methods 23* Creates a new class with given methods
24* Methods whose names start with __ are passed directly to the metatable.
26\*-------------------------------------------------------------------------*/ 25\*-------------------------------------------------------------------------*/
27void aux_newclass(lua_State *L, const char *classname, luaL_reg *func) 26void aux_newclass(lua_State *L, const char *classname, luaL_reg *func) {
28{
29 luaL_newmetatable(L, classname); /* mt */ 27 luaL_newmetatable(L, classname); /* mt */
30 /* create __index table to place methods */ 28 /* create __index table to place methods */
31 lua_pushstring(L, "__index"); /* mt,"__index" */ 29 lua_pushstring(L, "__index"); /* mt,"__index" */
@@ -46,10 +44,30 @@ void aux_newclass(lua_State *L, const char *classname, luaL_reg *func)
46} 44}
47 45
48/*-------------------------------------------------------------------------*\ 46/*-------------------------------------------------------------------------*\
47* Prints the value of a class in a nice way
48\*-------------------------------------------------------------------------*/
49int aux_tostring(lua_State *L) {
50 char buf[32];
51 if (!lua_getmetatable(L, 1)) goto error;
52 lua_pushstring(L, "__index");
53 lua_gettable(L, -2);
54 if (!lua_istable(L, -1)) goto error;
55 lua_pushstring(L, "class");
56 lua_gettable(L, -2);
57 if (!lua_isstring(L, -1)) goto error;
58 sprintf(buf, "%p", lua_touserdata(L, 1));
59 lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf);
60 return 1;
61error:
62 lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'");
63 lua_error(L);
64 return 1;
65}
66
67/*-------------------------------------------------------------------------*\
49* Insert class into group 68* Insert class into group
50\*-------------------------------------------------------------------------*/ 69\*-------------------------------------------------------------------------*/
51void aux_add2group(lua_State *L, const char *classname, const char *groupname) 70void aux_add2group(lua_State *L, const char *classname, const char *groupname) {
52{
53 luaL_getmetatable(L, classname); 71 luaL_getmetatable(L, classname);
54 lua_pushstring(L, groupname); 72 lua_pushstring(L, groupname);
55 lua_pushboolean(L, 1); 73 lua_pushboolean(L, 1);
@@ -60,8 +78,7 @@ void aux_add2group(lua_State *L, const char *classname, const char *groupname)
60/*-------------------------------------------------------------------------*\ 78/*-------------------------------------------------------------------------*\
61* Make sure argument is a boolean 79* Make sure argument is a boolean
62\*-------------------------------------------------------------------------*/ 80\*-------------------------------------------------------------------------*/
63int aux_checkboolean(lua_State *L, int objidx) 81int aux_checkboolean(lua_State *L, int objidx) {
64{
65 if (!lua_isboolean(L, objidx)) 82 if (!lua_isboolean(L, objidx))
66 luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); 83 luaL_typerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
67 return lua_toboolean(L, objidx); 84 return lua_toboolean(L, objidx);
@@ -71,8 +88,7 @@ int aux_checkboolean(lua_State *L, int objidx)
71* Return userdata pointer if object belongs to a given class, abort with 88* Return userdata pointer if object belongs to a given class, abort with
72* error otherwise 89* error otherwise
73\*-------------------------------------------------------------------------*/ 90\*-------------------------------------------------------------------------*/
74void *aux_checkclass(lua_State *L, const char *classname, int objidx) 91void *aux_checkclass(lua_State *L, const char *classname, int objidx) {
75{
76 void *data = aux_getclassudata(L, classname, objidx); 92 void *data = aux_getclassudata(L, classname, objidx);
77 if (!data) { 93 if (!data) {
78 char msg[45]; 94 char msg[45];
@@ -86,8 +102,7 @@ void *aux_checkclass(lua_State *L, const char *classname, int objidx)
86* Return userdata pointer if object belongs to a given group, abort with 102* Return userdata pointer if object belongs to a given group, abort with
87* error otherwise 103* error otherwise
88\*-------------------------------------------------------------------------*/ 104\*-------------------------------------------------------------------------*/
89void *aux_checkgroup(lua_State *L, const char *groupname, int objidx) 105void *aux_checkgroup(lua_State *L, const char *groupname, int objidx) {
90{
91 void *data = aux_getgroupudata(L, groupname, objidx); 106 void *data = aux_getgroupudata(L, groupname, objidx);
92 if (!data) { 107 if (!data) {
93 char msg[45]; 108 char msg[45];
@@ -100,8 +115,7 @@ void *aux_checkgroup(lua_State *L, const char *groupname, int objidx)
100/*-------------------------------------------------------------------------*\ 115/*-------------------------------------------------------------------------*\
101* Set object class 116* Set object class
102\*-------------------------------------------------------------------------*/ 117\*-------------------------------------------------------------------------*/
103void aux_setclass(lua_State *L, const char *classname, int objidx) 118void aux_setclass(lua_State *L, const char *classname, int objidx) {
104{
105 luaL_getmetatable(L, classname); 119 luaL_getmetatable(L, classname);
106 if (objidx < 0) objidx--; 120 if (objidx < 0) objidx--;
107 lua_setmetatable(L, objidx); 121 lua_setmetatable(L, objidx);
@@ -111,8 +125,7 @@ void aux_setclass(lua_State *L, const char *classname, int objidx)
111* Get a userdata pointer if object belongs to a given group. Return NULL 125* Get a userdata pointer if object belongs to a given group. Return NULL
112* otherwise 126* otherwise
113\*-------------------------------------------------------------------------*/ 127\*-------------------------------------------------------------------------*/
114void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) 128void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) {
115{
116 if (!lua_getmetatable(L, objidx)) 129 if (!lua_getmetatable(L, objidx))
117 return NULL; 130 return NULL;
118 lua_pushstring(L, groupname); 131 lua_pushstring(L, groupname);
@@ -130,7 +143,6 @@ void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx)
130* Get a userdata pointer if object belongs to a given class. Return NULL 143* Get a userdata pointer if object belongs to a given class. Return NULL
131* otherwise 144* otherwise
132\*-------------------------------------------------------------------------*/ 145\*-------------------------------------------------------------------------*/
133void *aux_getclassudata(lua_State *L, const char *classname, int objidx) 146void *aux_getclassudata(lua_State *L, const char *classname, int objidx) {
134{
135 return luaL_checkudata(L, objidx, classname); 147 return luaL_checkudata(L, objidx, classname);
136} 148}
diff --git a/src/auxiliar.h b/src/auxiliar.h
index bc45182..70f4704 100644
--- a/src/auxiliar.h
+++ b/src/auxiliar.h
@@ -2,26 +2,28 @@
2#define AUX_H 2#define AUX_H
3/*=========================================================================*\ 3/*=========================================================================*\
4* Auxiliar routines for class hierarchy manipulation 4* Auxiliar routines for class hierarchy manipulation
5* LuaSocket toolkit 5* LuaSocket toolkit (but completely independent of other LuaSocket modules)
6* 6*
7* A LuaSocket class is a name associated with Lua metatables. A LuaSocket 7* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
8* group is a name associated to a class. A class can belong to any number 8* group is a name associated with a class. A class can belong to any number
9* of groups. This module provides the functionality to: 9* of groups. This module provides the functionality to:
10* 10*
11* - create new classes 11* - create new classes
12* - add classes to groups 12* - add classes to groups
13* - set the class of object 13* - set the class of objects
14* - check if an object belongs to a given class or group 14* - check if an object belongs to a given class or group
15* - get the userdata associated to objects
16* - print objects in a pretty way
15* 17*
16* LuaSocket class names follow the convention <module>{<class>}. Modules 18* LuaSocket class names follow the convention <module>{<class>}. Modules
17* can define any number of classes and groups. The module tcp.c, for 19* can define any number of classes and groups. The module tcp.c, for
18* example, defines the classes tcp{master}, tcp{client} and tcp{server} and 20* example, defines the classes tcp{master}, tcp{client} and tcp{server} and
19* the groups tcp{client, server} and tcp{any}. Module functions can then 21* the groups tcp{client,server} and tcp{any}. Module functions can then
20* perform type-checking on it's arguments by either class or group. 22* perform type-checking on their arguments by either class or group.
21* 23*
22* LuaSocket metatables define the __index metamethod as being a table. This 24* LuaSocket metatables define the __index metamethod as being a table. This
23* table has one field for each method supported by the class. In DEBUG 25* table has one field for each method supported by the class, and a field
24* mode, it also has one field with the class name. 26* "class" with the class name.
25* 27*
26* The mapping from class name to the corresponding metatable and the 28* The mapping from class name to the corresponding metatable and the
27* reverse mapping are done using lauxlib. 29* reverse mapping are done using lauxlib.
@@ -32,14 +34,6 @@
32#include <lua.h> 34#include <lua.h>
33#include <lauxlib.h> 35#include <lauxlib.h>
34 36
35/* min and max macros */
36#ifndef MIN
37#define MIN(x, y) ((x) < (y) ? x : y)
38#endif
39#ifndef MAX
40#define MAX(x, y) ((x) > (y) ? x : y)
41#endif
42
43int aux_open(lua_State *L); 37int aux_open(lua_State *L);
44void aux_newclass(lua_State *L, const char *classname, luaL_reg *func); 38void aux_newclass(lua_State *L, const char *classname, luaL_reg *func);
45void aux_add2group(lua_State *L, const char *classname, const char *group); 39void aux_add2group(lua_State *L, const char *classname, const char *group);
@@ -49,5 +43,6 @@ void *aux_checkgroup(lua_State *L, const char *groupname, int objidx);
49void *aux_getclassudata(lua_State *L, const char *groupname, int objidx); 43void *aux_getclassudata(lua_State *L, const char *groupname, int objidx);
50void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx); 44void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx);
51int aux_checkboolean(lua_State *L, int objidx); 45int aux_checkboolean(lua_State *L, int objidx);
46int aux_tostring(lua_State *L);
52 47
53#endif /* AUX_H */ 48#endif /* AUX_H */
diff --git a/src/buffer.c b/src/buffer.c
index b771047..fd885a2 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -7,7 +7,6 @@
7#include <lua.h> 7#include <lua.h>
8#include <lauxlib.h> 8#include <lauxlib.h>
9 9
10#include "auxiliar.h"
11#include "buffer.h" 10#include "buffer.h"
12 11
13/*=========================================================================*\ 12/*=========================================================================*\
@@ -20,6 +19,14 @@ static int buf_get(p_buf buf, const char **data, size_t *count);
20static void buf_skip(p_buf buf, size_t count); 19static void buf_skip(p_buf buf, size_t count);
21static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent); 20static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent);
22 21
22/* min and max macros */
23#ifndef MIN
24#define MIN(x, y) ((x) < (y) ? x : y)
25#endif
26#ifndef MAX
27#define MAX(x, y) ((x) > (y) ? x : y)
28#endif
29
23/*=========================================================================*\ 30/*=========================================================================*\
24* Exported functions 31* Exported functions
25\*=========================================================================*/ 32\*=========================================================================*/
diff --git a/src/except.c b/src/except.c
new file mode 100644
index 0000000..c9eb20e
--- /dev/null
+++ b/src/except.c
@@ -0,0 +1,52 @@
1#include <lauxlib.h>
2#include <stdio.h>
3
4#include "except.h"
5
6static int global_try(lua_State *L);
7static int global_protect(lua_State *L);
8static int protected(lua_State *L);
9
10static luaL_reg func[] = {
11 {"try", global_try},
12 {"protect", global_protect},
13 {NULL, NULL}
14};
15
16/*-------------------------------------------------------------------------*\
17* Exception handling: try method
18\*-------------------------------------------------------------------------*/
19static int global_try(lua_State *L) {
20 if (lua_isnil(L, 1) || (lua_isboolean(L, 1) && !lua_toboolean(L, 1))) {
21 lua_settop(L, 2);
22 lua_error(L);
23 return 0;
24 } else return lua_gettop(L);
25}
26
27/*-------------------------------------------------------------------------*\
28* Exception handling: protect factory
29\*-------------------------------------------------------------------------*/
30static int protected(lua_State *L) {
31 lua_pushvalue(L, lua_upvalueindex(1));
32 lua_insert(L, 1);
33 if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
34 lua_pushnil(L);
35 lua_insert(L, 1);
36 return 2;
37 } else return lua_gettop(L);
38}
39
40static int global_protect(lua_State *L) {
41 lua_insert(L, 1);
42 lua_pushcclosure(L, protected, 1);
43 return 1;
44}
45
46/*-------------------------------------------------------------------------*\
47* Init module
48\*-------------------------------------------------------------------------*/
49int except_open(lua_State *L) {
50 luaL_openlib(L, NULL, func, 0);
51 return 0;
52}
diff --git a/src/except.h b/src/except.h
new file mode 100644
index 0000000..2c57b27
--- /dev/null
+++ b/src/except.h
@@ -0,0 +1,35 @@
1#ifndef EXCEPT_H
2#define EXCEPT_H
3/*=========================================================================*\
4* Exception control
5* LuaSocket toolkit (but completely independent from other modules)
6*
7* This provides support for simple exceptions in Lua. During the
8* development of the HTTP/FTP/SMTP support, it became aparent that
9* error checking was taking a substantial amount of the coding. These
10* function greatly simplify the task of checking errors.
11*
12* The main idea is that functions should return nil as its first return
13* value when it finds an error, and return an error message (or value)
14* following nil. In case of success, as long as the first value is not nil,
15* the other values don't matter.
16*
17* The idea is to nest function calls with the "try" function. This function
18* checks the first value, and calls "error" on the second if the first is
19* nil. Otherwise, it returns all values it received.
20*
21* The protect function returns a new function that behaves exactly like the
22* function it receives, but the new function doesn't throw exceptions: it
23* returns nil followed by the error message instead.
24*
25* With these two function, it's easy to write functions that throw
26* exceptions on error, but that don't interrupt the user script.
27*
28* RCS ID: $Id$
29\*=========================================================================*/
30
31#include <lua.h>
32
33int except_open(lua_State *L);
34
35#endif
diff --git a/src/ftp.lua b/src/ftp.lua
index 79772f8..c130d1a 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -7,7 +7,7 @@
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8 8
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10-- Load other required modules 10-- Load required modules
11----------------------------------------------------------------------------- 11-----------------------------------------------------------------------------
12local socket = require("socket") 12local socket = require("socket")
13local ltn12 = require("ltn12") 13local ltn12 = require("ltn12")
@@ -17,10 +17,7 @@ local tp = require("tp")
17----------------------------------------------------------------------------- 17-----------------------------------------------------------------------------
18-- Setup namespace 18-- Setup namespace
19----------------------------------------------------------------------------- 19-----------------------------------------------------------------------------
20local ftp = {} 20_LOADED["ftp"] = getfenv(1)
21-- make all module globals fall into namespace
22setmetatable(ftp, { __index = _G })
23setfenv(1, ftp)
24 21
25----------------------------------------------------------------------------- 22-----------------------------------------------------------------------------
26-- Program constants 23-- Program constants
@@ -32,9 +29,7 @@ PORT = 21
32-- this is the default anonymous password. used when no password is 29-- this is the default anonymous password. used when no password is
33-- provided in url. should be changed to your e-mail. 30-- provided in url. should be changed to your e-mail.
34USER = "ftp" 31USER = "ftp"
35EMAIL = "anonymous@anonymous.org" 32PASSWORD = "anonymous@anonymous.org"
36-- block size used in transfers
37BLOCKSIZE = 2048
38 33
39----------------------------------------------------------------------------- 34-----------------------------------------------------------------------------
40-- Low level FTP API 35-- Low level FTP API
@@ -42,7 +37,7 @@ BLOCKSIZE = 2048
42local metat = { __index = {} } 37local metat = { __index = {} }
43 38
44function open(server, port) 39function open(server, port)
45 local tp = socket.try(socket.tp.connect(server, port or PORT)) 40 local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT))
46 return setmetatable({tp = tp}, metat) 41 return setmetatable({tp = tp}, metat)
47end 42end
48 43
@@ -51,14 +46,17 @@ local function port(portt)
51end 46end
52 47
53local function pasv(pasvt) 48local function pasv(pasvt)
54 return socket.connect(pasvt.ip, pasvt.port) 49 local data = socket.try(socket.tcp())
50 socket.try(data:settimeout(TIMEOUT))
51 socket.try(data:connect(pasvt.ip, pasvt.port))
52 return data
55end 53end
56 54
57function metat.__index:login(user, password) 55function metat.__index:login(user, password)
58 socket.try(self.tp:command("user", user or USER)) 56 socket.try(self.tp:command("user", user or USER))
59 local code, reply = socket.try(self.tp:check{"2..", 331}) 57 local code, reply = socket.try(self.tp:check{"2..", 331})
60 if code == 331 then 58 if code == 331 then
61 socket.try(self.tp:command("pass", password or EMAIL)) 59 socket.try(self.tp:command("pass", password or PASSWORD))
62 socket.try(self.tp:check("2..")) 60 socket.try(self.tp:check("2.."))
63 end 61 end
64 return 1 62 return 1
@@ -104,6 +102,7 @@ function metat.__index:send(sendt)
104 socket.try(self.pasvt or self.portt, "need port or pasv first") 102 socket.try(self.pasvt or self.portt, "need port or pasv first")
105 if self.pasvt then data = socket.try(pasv(self.pasvt)) end 103 if self.pasvt then data = socket.try(pasv(self.pasvt)) end
106 local argument = sendt.argument or string.gsub(sendt.path, "^/", "") 104 local argument = sendt.argument or string.gsub(sendt.path, "^/", "")
105 if argument == "" then argument = nil end
107 local command = sendt.command or "stor" 106 local command = sendt.command or "stor"
108 socket.try(self.tp:command(command, argument)) 107 socket.try(self.tp:command(command, argument))
109 local code, reply = socket.try(self.tp:check{"2..", "1.."}) 108 local code, reply = socket.try(self.tp:check{"2..", "1.."})
@@ -133,6 +132,7 @@ function metat.__index:receive(recvt)
133 socket.try(self.pasvt or self.portt, "need port or pasv first") 132 socket.try(self.pasvt or self.portt, "need port or pasv first")
134 if self.pasvt then data = socket.try(pasv(self.pasvt)) end 133 if self.pasvt then data = socket.try(pasv(self.pasvt)) end
135 local argument = recvt.argument or string.gsub(recvt.path, "^/", "") 134 local argument = recvt.argument or string.gsub(recvt.path, "^/", "")
135 if argument == "" then argument = nil end
136 local command = recvt.command or "retr" 136 local command = recvt.command or "retr"
137 socket.try(self.tp:command(command, argument)) 137 socket.try(self.tp:command(command, argument))
138 local code = socket.try(self.tp:check{"1..", "2.."}) 138 local code = socket.try(self.tp:check{"1..", "2.."})
@@ -182,14 +182,14 @@ end
182-- High level FTP API 182-- High level FTP API
183----------------------------------------------------------------------------- 183-----------------------------------------------------------------------------
184local function tput(putt) 184local function tput(putt)
185 local ftp = socket.ftp.open(putt.host, putt.port) 185 local con = ftp.open(putt.host, putt.port)
186 ftp:greet() 186 con:greet()
187 ftp:login(putt.user, putt.password) 187 con:login(putt.user, putt.password)
188 if putt.type then ftp:type(putt.type) end 188 if putt.type then con:type(putt.type) end
189 ftp:pasv() 189 con:pasv()
190 ftp:send(putt) 190 con:send(putt)
191 ftp:quit() 191 con:quit()
192 return ftp:close() 192 return con:close()
193end 193end
194 194
195local default = { 195local default = {
@@ -198,15 +198,16 @@ local default = {
198} 198}
199 199
200local function parse(u) 200local function parse(u)
201 local putt = socket.try(url.parse(u, default)) 201 local t = socket.try(url.parse(u, default))
202 socket.try(putt.scheme == "ftp", "invalid scheme '" .. putt.scheme .. "'") 202 socket.try(t.scheme == "ftp", "invalid scheme '" .. t.scheme .. "'")
203 socket.try(putt.host, "invalid host") 203 socket.try(t.host, "invalid host")
204 local pat = "^type=(.)$" 204 local pat = "^type=(.)$"
205 if putt.params then 205 if t.params then
206 putt.type = socket.skip(2, string.find(putt.params, pat)) 206 t.type = socket.skip(2, string.find(t.params, pat))
207 socket.try(putt.type == "a" or putt.type == "i") 207 socket.try(t.type == "a" or t.type == "i",
208 "invalid type '" .. t.type .. "'")
208 end 209 end
209 return putt 210 return t
210end 211end
211 212
212local function sput(u, body) 213local function sput(u, body)
@@ -221,17 +222,17 @@ put = socket.protect(function(putt, body)
221end) 222end)
222 223
223local function tget(gett) 224local function tget(gett)
224 local ftp = socket.ftp.open(gett.host, gett.port) 225 local con = ftp.open(gett.host, gett.port)
225 ftp:greet() 226 con:greet()
226 ftp:login(gett.user, gett.password) 227 con:login(gett.user, gett.password)
227 if gett.type then ftp:type(gett.type) end 228 if gett.type then con:type(gett.type) end
228 ftp:pasv() 229 con:pasv()
229 ftp:receive(gett) 230 con:receive(gett)
230 ftp:quit() 231 con:quit()
231 return ftp:close() 232 return con:close()
232end 233end
233 234
234local function sget(u, body) 235local function sget(u)
235 local gett = parse(u) 236 local gett = parse(u)
236 local t = {} 237 local t = {}
237 gett.sink = ltn12.sink.table(t) 238 gett.sink = ltn12.sink.table(t)
@@ -240,7 +241,7 @@ local function sget(u, body)
240end 241end
241 242
242get = socket.protect(function(gett) 243get = socket.protect(function(gett)
243 if type(gett) == "string" then return sget(gett, body) 244 if type(gett) == "string" then return sget(gett)
244 else return tget(gett) end 245 else return tget(gett) end
245end) 246end)
246 247
diff --git a/src/http.lua b/src/http.lua
index ebe6b54..129b562 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -7,7 +7,7 @@
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8 8
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10-- Load other required modules 10-- Load required modules
11------------------------------------------------------------------------------- 11-------------------------------------------------------------------------------
12local socket = require("socket") 12local socket = require("socket")
13local ltn12 = require("ltn12") 13local ltn12 = require("ltn12")
@@ -17,42 +17,68 @@ local url = require("url")
17----------------------------------------------------------------------------- 17-----------------------------------------------------------------------------
18-- Setup namespace 18-- Setup namespace
19------------------------------------------------------------------------------- 19-------------------------------------------------------------------------------
20http = {} 20_LOADED["http"] = getfenv(1)
21-- make all module globals fall into namespace
22setmetatable(http, { __index = _G })
23setfenv(1, http)
24 21
25----------------------------------------------------------------------------- 22-----------------------------------------------------------------------------
26-- Program constants 23-- Program constants
27----------------------------------------------------------------------------- 24-----------------------------------------------------------------------------
28-- connection timeout in seconds 25-- connection timeout in seconds
29TIMEOUT = 60 26TIMEOUT = 4
30-- default port for document retrieval 27-- default port for document retrieval
31PORT = 80 28PORT = 80
32-- user agent field sent in request 29-- user agent field sent in request
33USERAGENT = socket.version 30USERAGENT = socket.VERSION
34-- block size used in transfers 31-- block size used in transfers
35BLOCKSIZE = 2048 32BLOCKSIZE = 2048
36 33
37----------------------------------------------------------------------------- 34-----------------------------------------------------------------------------
38-- Function return value selectors 35-- Low level HTTP API
39----------------------------------------------------------------------------- 36-----------------------------------------------------------------------------
40local function second(a, b) 37local metat = { __index = {} }
41 return b 38
39function open(host, port)
40 local con = socket.try(socket.tcp())
41 socket.try(con:settimeout(TIMEOUT))
42 port = port or PORT
43 socket.try(con:connect(host, port))
44 return setmetatable({ con = con }, metat)
45end
46
47function metat.__index:sendrequestline(method, uri)
48 local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
49 return socket.try(self.con:send(reqline))
42end 50end
43 51
44local function third(a, b, c) 52function metat.__index:sendheaders(headers)
45 return c 53 for i, v in pairs(headers) do
54 socket.try(self.con:send(i .. ": " .. v .. "\r\n"))
55 end
56 -- mark end of request headers
57 socket.try(self.con:send("\r\n"))
58 return 1
46end 59end
47 60
48local function receive_headers(reqt, respt, tmp) 61function metat.__index:sendbody(headers, source, step)
49 local sock = tmp.sock 62 source = source or ltn12.source.empty()
63 step = step or ltn12.pump.step
64 -- if we don't know the size in advance, send chunked and hope for the best
65 local mode
66 if headers["content-length"] then mode = "keep-open"
67 else mode = "http-chunked" end
68 return socket.try(ltn12.pump.all(source, socket.sink(mode, self.con), step))
69end
70
71function metat.__index:receivestatusline()
72 local status = socket.try(self.con:receive())
73 local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
74 return socket.try(tonumber(code), status)
75end
76
77function metat.__index:receiveheaders()
50 local line, name, value 78 local line, name, value
51 local headers = {} 79 local headers = {}
52 -- store results
53 respt.headers = headers
54 -- get first line 80 -- get first line
55 line = socket.try(sock:receive()) 81 line = socket.try(self.con:receive())
56 -- headers go until a blank line is found 82 -- headers go until a blank line is found
57 while line ~= "" do 83 while line ~= "" do
58 -- get field-name and value 84 -- get field-name and value
@@ -60,189 +86,137 @@ local function receive_headers(reqt, respt, tmp)
60 socket.try(name and value, "malformed reponse headers") 86 socket.try(name and value, "malformed reponse headers")
61 name = string.lower(name) 87 name = string.lower(name)
62 -- get next line (value might be folded) 88 -- get next line (value might be folded)
63 line = socket.try(sock:receive()) 89 line = socket.try(self.con:receive())
64 -- unfold any folded values 90 -- unfold any folded values
65 while string.find(line, "^%s") do 91 while string.find(line, "^%s") do
66 value = value .. line 92 value = value .. line
67 line = socket.try(sock:receive()) 93 line = socket.try(self.con:receive())
68 end 94 end
69 -- save pair in table 95 -- save pair in table
70 if headers[name] then headers[name] = headers[name] .. ", " .. value 96 if headers[name] then headers[name] = headers[name] .. ", " .. value
71 else headers[name] = value end 97 else headers[name] = value end
72 end 98 end
99 return headers
73end 100end
74 101
75local function receive_body(reqt, respt, tmp) 102function metat.__index:receivebody(headers, sink, step)
76 local sink = reqt.sink or ltn12.sink.null() 103 sink = sink or ltn12.sink.null()
77 local step = reqt.step or ltn12.pump.step 104 step = step or ltn12.pump.step
78 local source 105 local length = tonumber(headers["content-length"])
79 local te = respt.headers["transfer-encoding"] 106 local TE = headers["transfer-encoding"]
80 if te and te ~= "identity" then 107 local mode
81 -- get by chunked transfer-coding of message body 108 if TE and TE ~= "identity" then mode = "http-chunked"
82 source = socket.source("http-chunked", tmp.sock) 109 elseif tonumber(headers["content-length"]) then mode = "by-length"
83 elseif tonumber(respt.headers["content-length"]) then 110 else mode = "default" end
84 -- get by content-length 111 return socket.try(ltn12.pump.all(socket.source(mode, self.con, length),
85 local length = tonumber(respt.headers["content-length"]) 112 sink, step))
86 source = socket.source("by-length", tmp.sock, length)
87 else
88 -- get it all until connection closes
89 source = socket.source(tmp.sock)
90 end
91 socket.try(ltn12.pump.all(source, sink, step))
92end 113end
93 114
94local function send_headers(sock, headers) 115function metat.__index:close()
95 -- send request headers 116 return self.con:close()
96 for i, v in pairs(headers) do
97 socket.try(sock:send(i .. ": " .. v .. "\r\n"))
98 end
99 -- mark end of request headers
100 socket.try(sock:send("\r\n"))
101end 117end
102 118
103local function should_receive_body(reqt, respt, tmp) 119-----------------------------------------------------------------------------
104 if reqt.method == "HEAD" then return nil end 120-- High level HTTP API
105 if respt.code == 204 or respt.code == 304 then return nil end 121-----------------------------------------------------------------------------
106 if respt.code >= 100 and respt.code < 200 then return nil end 122local function uri(reqt)
107 return 1 123 local u = reqt
108end 124 if not reqt.proxy and not PROXY then
109 125 u = {
110local function receive_status(reqt, respt, tmp) 126 path = reqt.path,
111 local status = socket.try(tmp.sock:receive()) 127 params = reqt.params,
112 local code = third(string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) 128 query = reqt.query,
113 -- store results 129 fragment = reqt.fragment
114 respt.code, respt.status = tonumber(code), status
115end
116
117local function request_uri(reqt, respt, tmp)
118 local u = tmp.parsed
119 if not reqt.proxy then
120 local parsed = tmp.parsed
121 u = {
122 path = parsed.path,
123 params = parsed.params,
124 query = parsed.query,
125 fragment = parsed.fragment
126 } 130 }
127 end 131 end
128 return url.build(u) 132 return url.build(u)
129end 133end
130 134
131local function send_request(reqt, respt, tmp) 135local function adjustheaders(headers, host)
132 local uri = request_uri(reqt, respt, tmp)
133 local headers = tmp.headers
134 local step = reqt.step or ltn12.pump.step
135 -- send request line
136 socket.try(tmp.sock:send((reqt.method or "GET")
137 .. " " .. uri .. " HTTP/1.1\r\n"))
138 if reqt.source and not headers["content-length"] then
139 headers["transfer-encoding"] = "chunked"
140 end
141 send_headers(tmp.sock, headers)
142 -- send request message body, if any
143 if not reqt.source then return end
144 if headers["content-length"] then
145 socket.try(ltn12.pump.all(reqt.source,
146 socket.sink(tmp.sock), step))
147 else
148 socket.try(ltn12.pump.all(reqt.source,
149 socket.sink("http-chunked", tmp.sock), step))
150 end
151end
152
153local function open(reqt, respt, tmp)
154 local proxy = reqt.proxy or PROXY
155 local host, port
156 if proxy then
157 local pproxy = url.parse(proxy)
158 socket.try(pproxy.port and pproxy.host, "invalid proxy")
159 host, port = pproxy.host, pproxy.port
160 else
161 host, port = tmp.parsed.host, tmp.parsed.port
162 end
163 -- store results
164 tmp.sock = socket.try(socket.tcp())
165 socket.try(tmp.sock:settimeout(reqt.timeout or TIMEOUT))
166 socket.try(tmp.sock:connect(host, port))
167end
168
169local function adjust_headers(reqt, respt, tmp)
170 local lower = {} 136 local lower = {}
171 -- override with user values 137 -- override with user values
172 for i,v in (reqt.headers or lower) do 138 for i,v in (headers or lower) do
173 lower[string.lower(i)] = v 139 lower[string.lower(i)] = v
174 end 140 end
175 lower["user-agent"] = lower["user-agent"] or USERAGENT 141 lower["user-agent"] = lower["user-agent"] or USERAGENT
176 -- these cannot be overriden 142 -- these cannot be overriden
177 lower["host"] = tmp.parsed.host 143 lower["host"] = host
178 lower["connection"] = "close" 144 return lower
179 -- store results
180 tmp.headers = lower
181end 145end
182 146
183local function parse_url(reqt, respt, tmp) 147local function adjustrequest(reqt)
184 -- parse url with default fields 148 -- parse url with default fields
185 local parsed = url.parse(reqt.url, { 149 local parsed = url.parse(reqt.url, {
186 host = "", 150 host = "",
187 port = PORT, 151 port = PORT,
188 path ="/", 152 path ="/",
189 scheme = "http" 153 scheme = "http"
190 }) 154 })
191 -- scheme has to be http 155 -- explicit info in reqt overrides that given by the URL
192 socket.try(parsed.scheme == "http", 156 for i,v in reqt do parsed[i] = v end
193 string.format("unknown scheme '%s'", parsed.scheme)) 157 -- compute uri if user hasn't overriden
194 -- explicit authentication info overrides that given by the URL 158 parsed.uri = parsed.uri or uri(parsed)
195 parsed.user = reqt.user or parsed.user 159 -- adjust headers in request
196 parsed.password = reqt.password or parsed.password 160 parsed.headers = adjustheaders(parsed.headers, parsed.host)
197 -- store results 161 return parsed
198 tmp.parsed = parsed
199end 162end
200 163
201-- forward declaration 164local function shouldredirect(reqt, respt)
202local request_p 165 return (reqt.redirect ~= false) and
166 (respt.code == 301 or respt.code == 302) and
167 (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
168 and (not reqt.nredirects or reqt.nredirects < 5)
169end
203 170
204local function should_authorize(reqt, respt, tmp) 171local function shouldauthorize(reqt, respt)
205 -- if there has been an authorization attempt, it must have failed 172 -- if there has been an authorization attempt, it must have failed
206 if reqt.headers and reqt.headers["authorization"] then return nil end 173 if reqt.headers and reqt.headers["authorization"] then return nil end
207 -- if last attempt didn't fail due to lack of authentication, 174 -- if last attempt didn't fail due to lack of authentication,
208 -- or we don't have authorization information, we can't retry 175 -- or we don't have authorization information, we can't retry
209 return respt.code == 401 and tmp.parsed.user and tmp.parsed.password 176 return respt.code == 401 and reqt.user and reqt.password
210end 177end
211 178
212local function clone(headers) 179local function shouldreceivebody(reqt, respt)
213 if not headers then return nil end 180 if reqt.method == "HEAD" then return nil end
214 local copy = {} 181 local code = respt.code
215 for i,v in pairs(headers) do 182 if code == 204 or code == 304 then return nil end
216 copy[i] = v 183 if code >= 100 and code < 200 then return nil end
217 end 184 return 1
218 return copy
219end 185end
220 186
221local function authorize(reqt, respt, tmp) 187local requestp, authorizep, redirectp
222 local headers = clone(reqt.headers) or {} 188
223 headers["authorization"] = "Basic " .. 189function requestp(reqt)
224 (mime.b64(tmp.parsed.user .. ":" .. tmp.parsed.password)) 190 local reqt = adjustrequest(reqt)
225 local autht = { 191 local respt = {}
226 method = reqt.method, 192 local con = open(reqt.host, reqt.port)
227 url = reqt.url, 193 con:sendrequestline(reqt.method, reqt.uri)
228 source = reqt.source, 194 con:sendheaders(reqt.headers)
229 sink = reqt.sink, 195 con:sendbody(reqt.headers, reqt.source, reqt.step)
230 headers = headers, 196 respt.code, respt.status = con:receivestatusline()
231 timeout = reqt.timeout, 197 respt.headers = con:receiveheaders()
232 proxy = reqt.proxy, 198 if shouldredirect(reqt, respt) then
233 } 199 con:close()
234 request_p(autht, respt, tmp) 200 return redirectp(reqt, respt)
201 elseif shouldauthorize(reqt, respt) then
202 con:close()
203 return authorizep(reqt, respt)
204 elseif shouldreceivebody(reqt, respt) then
205 con:receivebody(respt.headers, reqt.sink, reqt.step)
206 end
207 con:close()
208 return respt
235end 209end
236 210
237local function should_redirect(reqt, respt, tmp) 211function authorizep(reqt, respt)
238 return (reqt.redirect ~= false) and 212 local auth = "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
239 (respt.code == 301 or respt.code == 302) and 213 reqt.headers["authorization"] = auth
240 (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") 214 return requestp(reqt)
241 and (not tmp.nredirects or tmp.nredirects < 5)
242end 215end
243 216
244local function redirect(reqt, respt, tmp) 217function redirectp(reqt, respt)
245 tmp.nredirects = (tmp.nredirects or 0) + 1 218 -- we create a new table to get rid of anything we don't
219 -- absolutely need, including authentication info
246 local redirt = { 220 local redirt = {
247 method = reqt.method, 221 method = reqt.method,
248 -- the RFC says the redirect URL has to be absolute, but some 222 -- the RFC says the redirect URL has to be absolute, but some
@@ -251,69 +225,38 @@ local function redirect(reqt, respt, tmp)
251 source = reqt.source, 225 source = reqt.source,
252 sink = reqt.sink, 226 sink = reqt.sink,
253 headers = reqt.headers, 227 headers = reqt.headers,
254 timeout = reqt.timeout, 228 proxy = reqt.proxy,
255 proxy = reqt.proxy 229 nredirects = (reqt.nredirects or 0) + 1
256 } 230 }
257 request_p(redirt, respt, tmp) 231 respt = requestp(redirt)
258 -- we pass the location header as a clue we redirected 232 -- we pass the location header as a clue we redirected
259 if respt.headers then respt.headers.location = redirt.url end 233 if respt.headers then respt.headers.location = redirt.url end
260end
261
262local function skip_continue(reqt, respt, tmp)
263 if respt.code == 100 then
264 receive_status(reqt, respt, tmp)
265 end
266end
267
268-- execute a request of through an exception
269function request_p(reqt, respt, tmp)
270 parse_url(reqt, respt, tmp)
271 adjust_headers(reqt, respt, tmp)
272 open(reqt, respt, tmp)
273 send_request(reqt, respt, tmp)
274 receive_status(reqt, respt, tmp)
275 skip_continue(reqt, respt, tmp)
276 receive_headers(reqt, respt, tmp)
277 if should_redirect(reqt, respt, tmp) then
278 tmp.sock:close()
279 redirect(reqt, respt, tmp)
280 elseif should_authorize(reqt, respt, tmp) then
281 tmp.sock:close()
282 authorize(reqt, respt, tmp)
283 elseif should_receive_body(reqt, respt, tmp) then
284 receive_body(reqt, respt, tmp)
285 end
286end
287
288function request(reqt)
289 local respt, tmp = {}, {}
290 local s, e = pcall(request_p, reqt, respt, tmp)
291 if not s then respt.error = e end
292 if tmp.sock then tmp.sock:close() end
293 return respt 234 return respt
294end 235end
295 236
296function get(u) 237request = socket.protect(requestp)
238
239get = socket.protect(function(u)
297 local t = {} 240 local t = {}
298 respt = request { 241 local respt = requestp {
299 url = u, 242 url = u,
300 sink = ltn12.sink.table(t) 243 sink = ltn12.sink.table(t)
301 } 244 }
302 return (table.getn(t) > 0 or nil) and table.concat(t), respt.headers, 245 return (table.getn(t) > 0 or nil) and table.concat(t), respt.headers,
303 respt.code, respt.error 246 respt.code
304end 247end)
305 248
306function post(u, body) 249post = socket.protect(function(u, body)
307 local t = {} 250 local t = {}
308 respt = request { 251 local respt = requestp {
309 url = u, 252 url = u,
310 method = "POST", 253 method = "POST",
311 source = ltn12.source.string(body), 254 source = ltn12.source.string(body),
312 sink = ltn12.sink.table(t), 255 sink = ltn12.sink.table(t),
313 headers = { ["content-length"] = string.len(body) } 256 headers = { ["content-length"] = string.len(body) }
314 } 257 }
315 return (table.getn(t) > 0 or nil) and table.concat(t), 258 return (table.getn(t) > 0 or nil) and table.concat(t),
316 respt.headers, respt.code, respt.error 259 respt.headers, respt.code
317end 260end)
318 261
319return http 262return http
diff --git a/src/inet.c b/src/inet.c
index 3a57441..62c67f1 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -10,7 +10,6 @@
10#include <lua.h> 10#include <lua.h>
11#include <lauxlib.h> 11#include <lauxlib.h>
12 12
13#include "luasocket.h"
14#include "inet.h" 13#include "inet.h"
15 14
16/*=========================================================================*\ 15/*=========================================================================*\
diff --git a/src/ltn12.lua b/src/ltn12.lua
index 41855f0..6228247 100644
--- a/src/ltn12.lua
+++ b/src/ltn12.lua
@@ -8,9 +8,8 @@
8----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
9-- Setup namespace 9-- Setup namespace
10----------------------------------------------------------------------------- 10-----------------------------------------------------------------------------
11local ltn12 = {} 11_LOADED["ltn12"] = getfenv(1)
12setmetatable(ltn12, { __index = _G }) 12
13setfenv(1, ltn12)
14filter = {} 13filter = {}
15source = {} 14source = {}
16sink = {} 15sink = {}
@@ -19,10 +18,6 @@ pump = {}
19-- 2048 seems to be better in windows... 18-- 2048 seems to be better in windows...
20BLOCKSIZE = 2048 19BLOCKSIZE = 2048
21 20
22local function shift(a, b, c)
23 return b, c
24end
25
26----------------------------------------------------------------------------- 21-----------------------------------------------------------------------------
27-- Filter stuff 22-- Filter stuff
28----------------------------------------------------------------------------- 23-----------------------------------------------------------------------------
@@ -53,7 +48,9 @@ local function chain2(f1, f2)
53 end 48 end
54 end) 49 end)
55 return function(chunk) 50 return function(chunk)
56 return shift(coroutine.resume(co, chunk)) 51 local ret, a, b = coroutine.resume(co, chunk)
52 if ret then return a, b
53 else return nil, a end
57 end 54 end
58end 55end
59 56
@@ -149,7 +146,9 @@ function source.chain(src, f)
149 end 146 end
150 end) 147 end)
151 return function() 148 return function()
152 return shift(coroutine.resume(co)) 149 local ret, a, b = coroutine.resume(co)
150 if ret then return a, b
151 else return nil, a end
153 end 152 end
154end 153end
155 154
@@ -166,7 +165,9 @@ function source.cat(...)
166 end 165 end
167 end) 166 end)
168 return function() 167 return function()
169 return shift(coroutine.resume(co)) 168 local ret, a, b = coroutine.resume(co)
169 if ret then return a, b
170 else return nil, a end
170 end 171 end
171end 172end
172 173
diff --git a/src/luasocket.c b/src/luasocket.c
index ca3a52c..2b0a1fa 100644
--- a/src/luasocket.c
+++ b/src/luasocket.c
@@ -26,7 +26,7 @@
26#include "luasocket.h" 26#include "luasocket.h"
27 27
28#include "auxiliar.h" 28#include "auxiliar.h"
29#include "base.h" 29#include "except.h"
30#include "timeout.h" 30#include "timeout.h"
31#include "buffer.h" 31#include "buffer.h"
32#include "inet.h" 32#include "inet.h"
@@ -35,11 +35,18 @@
35#include "select.h" 35#include "select.h"
36 36
37/*-------------------------------------------------------------------------*\ 37/*-------------------------------------------------------------------------*\
38* Modules 38* Internal function prototypes
39\*-------------------------------------------------------------------------*/
40static int global_skip(lua_State *L);
41static int global_unload(lua_State *L);
42static int base_open(lua_State *L);
43
44/*-------------------------------------------------------------------------*\
45* Modules and functions
39\*-------------------------------------------------------------------------*/ 46\*-------------------------------------------------------------------------*/
40static const luaL_reg mod[] = { 47static const luaL_reg mod[] = {
41 {"auxiliar", aux_open}, 48 {"auxiliar", aux_open},
42 {"base", base_open}, 49 {"except", except_open},
43 {"timeout", tm_open}, 50 {"timeout", tm_open},
44 {"buffer", buf_open}, 51 {"buffer", buf_open},
45 {"inet", inet_open}, 52 {"inet", inet_open},
@@ -49,11 +56,69 @@ static const luaL_reg mod[] = {
49 {NULL, NULL} 56 {NULL, NULL}
50}; 57};
51 58
59static luaL_reg func[] = {
60 {"skip", global_skip},
61 {"__unload", global_unload},
62 {NULL, NULL}
63};
64
65/*-------------------------------------------------------------------------*\
66* Skip a few arguments
67\*-------------------------------------------------------------------------*/
68static int global_skip(lua_State *L) {
69 int amount = luaL_checkint(L, 1);
70 int ret = lua_gettop(L) - amount - 1;
71 return ret >= 0 ? ret : 0;
72}
73
74/*-------------------------------------------------------------------------*\
75* Unloads the library
76\*-------------------------------------------------------------------------*/
77static int global_unload(lua_State *L) {
78 sock_close();
79 return 0;
80}
81
82/*-------------------------------------------------------------------------*\
83* Setup basic stuff.
84\*-------------------------------------------------------------------------*/
85static int base_open(lua_State *L) {
86 if (sock_open()) {
87 /* whoever is loading the library replaced the global environment
88 * with the namespace table */
89 lua_pushvalue(L, LUA_GLOBALSINDEX);
90 /* make sure library is still "requirable" if initialized staticaly */
91 lua_pushstring(L, "_LOADEDLIB");
92 lua_gettable(L, -2);
93 lua_pushstring(L, LUASOCKET_LIBNAME);
94 lua_pushcfunction(L, (lua_CFunction) luaopen_socket);
95 lua_settable(L, -3);
96 lua_pop(L, 1);
97#ifdef LUASOCKET_DEBUG
98 lua_pushstring(L, "DEBUG");
99 lua_pushboolean(L, 1);
100 lua_rawset(L, -3);
101#endif
102 /* make version string available to scripts */
103 lua_pushstring(L, "VERSION");
104 lua_pushstring(L, LUASOCKET_VERSION);
105 lua_rawset(L, -3);
106 /* export other functions */
107 luaL_openlib(L, NULL, func, 0);
108 return 1;
109 } else {
110 lua_pushstring(L, "unable to initialize library");
111 lua_error(L);
112 return 0;
113 }
114}
115
52/*-------------------------------------------------------------------------*\ 116/*-------------------------------------------------------------------------*\
53* Initializes all library modules. 117* Initializes all library modules.
54\*-------------------------------------------------------------------------*/ 118\*-------------------------------------------------------------------------*/
55LUASOCKET_API int luaopen_socket(lua_State *L) { 119LUASOCKET_API int luaopen_socket(lua_State *L) {
56 int i; 120 int i;
121 base_open(L);
57 for (i = 0; mod[i].name; i++) mod[i].func(L); 122 for (i = 0; mod[i].name; i++) mod[i].func(L);
58 return 1; 123 return 1;
59} 124}
diff --git a/src/luasocket.h b/src/luasocket.h
index 716b7ff..6d30605 100644
--- a/src/luasocket.h
+++ b/src/luasocket.h
@@ -25,6 +25,7 @@
25/*-------------------------------------------------------------------------*\ 25/*-------------------------------------------------------------------------*\
26* Initializes the library. 26* Initializes the library.
27\*-------------------------------------------------------------------------*/ 27\*-------------------------------------------------------------------------*/
28#define LUASOCKET_LIBNAME "socket"
28LUASOCKET_API int luaopen_socket(lua_State *L); 29LUASOCKET_API int luaopen_socket(lua_State *L);
29 30
30#endif /* LUASOCKET_H */ 31#endif /* LUASOCKET_H */
diff --git a/src/mime.c b/src/mime.c
index f42528c..5750714 100644
--- a/src/mime.c
+++ b/src/mime.c
@@ -76,7 +76,17 @@ static UC b64unbase[256];
76\*-------------------------------------------------------------------------*/ 76\*-------------------------------------------------------------------------*/
77MIME_API int luaopen_mime(lua_State *L) 77MIME_API int luaopen_mime(lua_State *L)
78{ 78{
79 lua_newtable(L); 79 /* whoever is loading the library replaced the global environment
80 * with the namespace table */
81 lua_pushvalue(L, LUA_GLOBALSINDEX);
82 /* make sure library is still "requirable" if initialized staticaly */
83 lua_pushstring(L, "_LOADEDLIB");
84 lua_gettable(L, -2);
85 lua_pushstring(L, MIME_LIBNAME);
86 lua_pushcfunction(L, (lua_CFunction) luaopen_mime);
87 lua_settable(L, -3);
88 lua_pop(L, 1);
89 /* export functions */
80 luaL_openlib(L, NULL, func, 0); 90 luaL_openlib(L, NULL, func, 0);
81 /* initialize lookup tables */ 91 /* initialize lookup tables */
82 qpsetup(qpclass, qpunbase); 92 qpsetup(qpclass, qpunbase);
diff --git a/src/mime.h b/src/mime.h
index 6febedf..b82d61a 100644
--- a/src/mime.h
+++ b/src/mime.h
@@ -19,6 +19,7 @@
19#define MIME_API extern 19#define MIME_API extern
20#endif 20#endif
21 21
22#define MIME_LIBNAME "mime"
22MIME_API int luaopen_mime(lua_State *L); 23MIME_API int luaopen_mime(lua_State *L);
23 24
24#endif /* MIME_H */ 25#endif /* MIME_H */
diff --git a/src/mime.lua b/src/mime.lua
index ecf310d..000404f 100644
--- a/src/mime.lua
+++ b/src/mime.lua
@@ -6,23 +6,15 @@
6----------------------------------------------------------------------------- 6-----------------------------------------------------------------------------
7 7
8----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
9-- Load MIME from dynamic library
10-- Comment these lines if you are loading static
11-----------------------------------------------------------------------------
12local open = assert(loadlib("mime", "luaopen_mime"))
13local mime = assert(open())
14
15-----------------------------------------------------------------------------
16-- Load other required modules 9-- Load other required modules
17----------------------------------------------------------------------------- 10-----------------------------------------------------------------------------
11local mime = requirelib("mime", "luaopen_mime", getfenv(1))
18local ltn12 = require("ltn12") 12local ltn12 = require("ltn12")
19 13
20----------------------------------------------------------------------------- 14-----------------------------------------------------------------------------
21-- Setup namespace 15-- Setup namespace
22----------------------------------------------------------------------------- 16-----------------------------------------------------------------------------
23-- make all module globals fall into mime namespace 17_LOADED["mime"] = mime
24setmetatable(mime, { __index = _G })
25setfenv(1, mime)
26 18
27-- encode, decode and wrap algorithm tables 19-- encode, decode and wrap algorithm tables
28encodet = {} 20encodet = {}
@@ -48,7 +40,7 @@ end
48 40
49encodet['quoted-printable'] = function(mode) 41encodet['quoted-printable'] = function(mode)
50 return ltn12.filter.cycle(qp, "", 42 return ltn12.filter.cycle(qp, "",
51 (mode == "binary") and "=0D=0A" or "\13\10") 43 (mode == "binary") and "=0D=0A" or "\r\n")
52end 44end
53 45
54-- define the decoding filters 46-- define the decoding filters
diff --git a/src/select.c b/src/select.c
index 1ebd82c..13f9d6e 100644
--- a/src/select.c
+++ b/src/select.c
@@ -9,26 +9,21 @@
9#include <lua.h> 9#include <lua.h>
10#include <lauxlib.h> 10#include <lauxlib.h>
11 11
12#include "luasocket.h"
13#include "socket.h" 12#include "socket.h"
14#include "auxiliar.h"
15#include "select.h" 13#include "select.h"
16 14
17/*=========================================================================*\ 15/*=========================================================================*\
18* Internal function prototypes. 16* Internal function prototypes.
19\*=========================================================================*/ 17\*=========================================================================*/
20static int meth_set(lua_State *L); 18static int getfd(lua_State *L);
21static int meth_isset(lua_State *L); 19static int dirty(lua_State *L);
22static int c_select(lua_State *L); 20static int collect_fd(lua_State *L, int tab, int max_fd, int itab, fd_set *set);
21static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
22static void return_fd(lua_State *L, fd_set *set, int max_fd,
23 int itab, int tab, int start);
24static void make_assoc(lua_State *L, int tab);
23static int global_select(lua_State *L); 25static int global_select(lua_State *L);
24 26
25/* fd_set object methods */
26static luaL_reg set[] = {
27 {"set", meth_set},
28 {"isset", meth_isset},
29 {NULL, NULL}
30};
31
32/* functions in library namespace */ 27/* functions in library namespace */
33static luaL_reg func[] = { 28static luaL_reg func[] = {
34 {"select", global_select}, 29 {"select", global_select},
@@ -36,22 +31,13 @@ static luaL_reg func[] = {
36}; 31};
37 32
38/*=========================================================================*\ 33/*=========================================================================*\
39* Internal function prototypes. 34* Exported functions
40\*=========================================================================*/ 35\*=========================================================================*/
41/*-------------------------------------------------------------------------*\ 36/*-------------------------------------------------------------------------*\
42* Initializes module 37* Initializes module
43\*-------------------------------------------------------------------------*/ 38\*-------------------------------------------------------------------------*/
44int select_open(lua_State *L) 39int select_open(lua_State *L) {
45{ 40 luaL_openlib(L, NULL, func, 0);
46 /* get select auxiliar lua function from lua code and register
47 * pass it as an upvalue to global_select */
48#ifdef LUASOCKET_COMPILED
49#include "select.lch"
50#else
51 lua_dofile(L, "select.lua");
52#endif
53 luaL_openlib(L, NULL, func, 1);
54 aux_newclass(L, "select{fd_set}", set);
55 return 0; 41 return 0;
56} 42}
57 43
@@ -61,64 +47,149 @@ int select_open(lua_State *L)
61/*-------------------------------------------------------------------------*\ 47/*-------------------------------------------------------------------------*\
62* Waits for a set of sockets until a condition is met or timeout. 48* Waits for a set of sockets until a condition is met or timeout.
63\*-------------------------------------------------------------------------*/ 49\*-------------------------------------------------------------------------*/
64static int global_select(lua_State *L) 50static int global_select(lua_State *L) {
65{ 51 int timeout, rtab, wtab, itab, max_fd, ret, ndirty;
66 fd_set *read_fd_set, *write_fd_set; 52 fd_set rset, wset;
67 /* make sure we have enough arguments (nil is the default) */ 53 FD_ZERO(&rset); FD_ZERO(&wset);
68 lua_settop(L, 3); 54 lua_settop(L, 3);
69 /* check timeout */ 55 timeout = lua_isnil(L, 3) ? -1 : (int)(luaL_checknumber(L, 3) * 1000);
70 if (!lua_isnil(L, 3) && !lua_isnumber(L, 3)) 56 lua_newtable(L); itab = lua_gettop(L);
71 luaL_argerror(L, 3, "number or nil expected"); 57 lua_newtable(L); rtab = lua_gettop(L);
72 /* select auxiliar lua function to be called comes first */ 58 lua_newtable(L); wtab = lua_gettop(L);
73 lua_pushvalue(L, lua_upvalueindex(1)); 59 max_fd = collect_fd(L, 1, -1, itab, &rset);
74 lua_insert(L, 1); 60 ndirty = check_dirty(L, 1, rtab, &rset);
75 /* pass fd_set objects */ 61 timeout = ndirty > 0? 0: timeout;
76 read_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set)); 62 max_fd = collect_fd(L, 2, max_fd, itab, &wset);
77 FD_ZERO(read_fd_set); 63 ret = sock_select(max_fd+1, &rset, &wset, NULL, timeout);
78 aux_setclass(L, "select{fd_set}", -1); 64 if (ret > 0 || (ret == 0 && ndirty > 0)) {
79 write_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set)); 65 return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
80 FD_ZERO(write_fd_set); 66 return_fd(L, &wset, max_fd+1, itab, wtab, 0);
81 aux_setclass(L, "select{fd_set}", -1); 67 make_assoc(L, rtab);
82 /* pass select auxiliar C function */ 68 make_assoc(L, wtab);
83 lua_pushcfunction(L, c_select); 69 return 2;
84 /* call select auxiliar lua function */ 70 } else if (ret == 0) {
85 lua_call(L, 6, 3); 71 lua_pushstring(L, "timeout");
86 return 3; 72 return 3;
73 } else {
74 lua_pushnil(L);
75 lua_pushnil(L);
76 lua_pushstring(L, "error");
77 return 3;
78 }
87} 79}
88 80
89/*=========================================================================*\ 81/*=========================================================================*\
90* Lua methods 82* Internal functions
91\*=========================================================================*/ 83\*=========================================================================*/
92static int meth_set(lua_State *L) 84static int getfd(lua_State *L) {
93{ 85 int fd = -1;
94 fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); 86 lua_pushstring(L, "getfd");
95 t_sock fd = (t_sock) lua_tonumber(L, 2); 87 lua_gettable(L, -2);
96 if (fd >= 0) FD_SET(fd, set); 88 if (!lua_isnil(L, -1)) {
97 return 0; 89 lua_pushvalue(L, -2);
90 lua_call(L, 1, 1);
91 if (lua_isnumber(L, -1))
92 fd = lua_tonumber(L, -1);
93 }
94 lua_pop(L, 1);
95 return fd;
98} 96}
99 97
100static int meth_isset(lua_State *L) 98static int dirty(lua_State *L) {
101{ 99 int is = 0;
102 fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); 100 lua_pushstring(L, "dirty");
103 t_sock fd = (t_sock) lua_tonumber(L, 2); 101 lua_gettable(L, -2);
104 if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); 102 if (!lua_isnil(L, -1)) {
105 else lua_pushnil(L); 103 lua_pushvalue(L, -2);
106 return 1; 104 lua_call(L, 1, 1);
105 is = lua_toboolean(L, -1);
106 }
107 lua_pop(L, 1);
108 return is;
107} 109}
108 110
109/*=========================================================================*\ 111static int collect_fd(lua_State *L, int tab, int max_fd,
110* Internal functions 112 int itab, fd_set *set) {
111\*=========================================================================*/ 113 int i = 1;
112static int c_select(lua_State *L) 114 if (lua_isnil(L, tab))
113{ 115 return max_fd;
114 int max_fd = (int) lua_tonumber(L, 1); 116 while (1) {
115 fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2); 117 int fd;
116 fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3); 118 lua_pushnumber(L, i);
117 int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); 119 lua_gettable(L, tab);
118 struct timeval tv; 120 if (lua_isnil(L, -1)) {
119 tv.tv_sec = timeout / 1000; 121 lua_pop(L, 1);
120 tv.tv_usec = (timeout % 1000) * 1000; 122 break;
121 lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL, 123 }
122 timeout < 0 ? NULL : &tv)); 124 fd = getfd(L);
123 return 1; 125 if (fd > 0) {
126 FD_SET(fd, set);
127 if (max_fd < fd) max_fd = fd;
128 lua_pushnumber(L, fd);
129 lua_pushvalue(L, -2);
130 lua_settable(L, itab);
131 }
132 lua_pop(L, 1);
133 i = i + 1;
134 }
135 return max_fd;
136}
137
138static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
139 int ndirty = 0, i = 1;
140 if (lua_isnil(L, tab))
141 return 0;
142 while (1) {
143 int fd;
144 lua_pushnumber(L, i);
145 lua_gettable(L, tab);
146 if (lua_isnil(L, -1)) {
147 lua_pop(L, 1);
148 break;
149 }
150 fd = getfd(L);
151 if (fd > 0 && dirty(L)) {
152 lua_pushnumber(L, ++ndirty);
153 lua_pushvalue(L, -2);
154 lua_settable(L, dtab);
155 FD_CLR(fd, set);
156 }
157 lua_pop(L, 1);
158 i = i + 1;
159 }
160 return ndirty;
161}
162
163static void return_fd(lua_State *L, fd_set *set, int max_fd,
164 int itab, int tab, int start) {
165 int fd;
166 for (fd = 0; fd < max_fd; fd++) {
167 if (FD_ISSET(fd, set)) {
168 lua_pushnumber(L, ++start);
169 lua_pushnumber(L, fd);
170 lua_gettable(L, itab);
171 lua_settable(L, tab);
172 }
173 }
174}
175
176static void make_assoc(lua_State *L, int tab) {
177 int i = 1, atab;
178 lua_newtable(L); atab = lua_gettop(L);
179 while (1) {
180 lua_pushnumber(L, i);
181 lua_gettable(L, tab);
182 if (!lua_isnil(L, -1)) {
183 lua_pushnumber(L, i);
184 lua_pushvalue(L, -2);
185 lua_settable(L, atab);
186 lua_pushnumber(L, i);
187 lua_settable(L, atab);
188 } else {
189 lua_pop(L, 1);
190 break;
191 }
192 i = i+1;
193 }
124} 194}
195
diff --git a/src/smtp.lua b/src/smtp.lua
index 7ae99a5..dc80c35 100644
--- a/src/smtp.lua
+++ b/src/smtp.lua
@@ -7,15 +7,9 @@
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8 8
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10-- Load SMTP from dynamic library 10-- Load required modules
11-- Comment these lines if you are loading static
12-----------------------------------------------------------------------------
13local open = assert(loadlib("smtp", "luaopen_smtp"))
14local smtp = assert(open())
15
16-----------------------------------------------------------------------------
17-- Load other required modules
18----------------------------------------------------------------------------- 11-----------------------------------------------------------------------------
12local smtp = requirelib("smtp")
19local socket = require("socket") 13local socket = require("socket")
20local ltn12 = require("ltn12") 14local ltn12 = require("ltn12")
21local tp = require("tp") 15local tp = require("tp")
@@ -23,10 +17,10 @@ local tp = require("tp")
23----------------------------------------------------------------------------- 17-----------------------------------------------------------------------------
24-- Setup namespace 18-- Setup namespace
25----------------------------------------------------------------------------- 19-----------------------------------------------------------------------------
26-- make all module globals fall into smtp namespace 20_LOADED["smtp"] = smtp
27setmetatable(smtp, { __index = _G })
28setfenv(1, smtp)
29 21
22-- timeout for connection
23TIMEOUT = 60
30-- default server used to send e-mails 24-- default server used to send e-mails
31SERVER = "localhost" 25SERVER = "localhost"
32-- default port 26-- default port
@@ -94,9 +88,7 @@ function metat.__index:send(mailt)
94end 88end
95 89
96function open(server, port) 90function open(server, port)
97 print(server or SERVER, port or PORT) 91 local tp = socket.try(tp.connect(server or SERVER, port or PORT, TIMEOUT))
98 local tp, error = tp.connect(server or SERVER, port or PORT)
99 if not tp then return nil, error end
100 return setmetatable({tp = tp}, metat) 92 return setmetatable({tp = tp}, metat)
101end 93end
102 94
@@ -121,7 +113,10 @@ local function send_multipart(mesgt)
121 coroutine.yield('content-type: multipart/mixed; boundary="' .. 113 coroutine.yield('content-type: multipart/mixed; boundary="' ..
122 bd .. '"\r\n\r\n') 114 bd .. '"\r\n\r\n')
123 -- send preamble 115 -- send preamble
124 if mesgt.body.preamble then coroutine.yield(mesgt.body.preamble) end 116 if mesgt.body.preamble then
117 coroutine.yield(mesgt.body.preamble)
118 coroutine.yield("\r\n")
119 end
125 -- send each part separated by a boundary 120 -- send each part separated by a boundary
126 for i, m in ipairs(mesgt.body) do 121 for i, m in ipairs(mesgt.body) do
127 coroutine.yield("\r\n--" .. bd .. "\r\n") 122 coroutine.yield("\r\n--" .. bd .. "\r\n")
@@ -130,7 +125,10 @@ local function send_multipart(mesgt)
130 -- send last boundary 125 -- send last boundary
131 coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") 126 coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
132 -- send epilogue 127 -- send epilogue
133 if mesgt.body.epilogue then coroutine.yield(mesgt.body.epilogue) end 128 if mesgt.body.epilogue then
129 coroutine.yield(mesgt.body.epilogue)
130 coroutine.yield("\r\n")
131 end
134end 132end
135 133
136-- yield message body from a source 134-- yield message body from a source
@@ -183,12 +181,12 @@ end
183-- set defaul headers 181-- set defaul headers
184local function adjust_headers(mesgt) 182local function adjust_headers(mesgt)
185 local lower = {} 183 local lower = {}
186 for i,v in (mesgt or lower) do 184 for i,v in (mesgt.headers or lower) do
187 lower[string.lower(i)] = v 185 lower[string.lower(i)] = v
188 end 186 end
189 lower["date"] = lower["date"] or 187 lower["date"] = lower["date"] or
190 os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE) 188 os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
191 lower["x-mailer"] = lower["x-mailer"] or socket.version 189 lower["x-mailer"] = lower["x-mailer"] or socket.VERSION
192 -- this can't be overriden 190 -- this can't be overriden
193 lower["mime-version"] = "1.0" 191 lower["mime-version"] = "1.0"
194 mesgt.headers = lower 192 mesgt.headers = lower
@@ -198,18 +196,22 @@ function message(mesgt)
198 adjust_headers(mesgt) 196 adjust_headers(mesgt)
199 -- create and return message source 197 -- create and return message source
200 local co = coroutine.create(function() send_message(mesgt) end) 198 local co = coroutine.create(function() send_message(mesgt) end)
201 return function() return socket.skip(1, coroutine.resume(co)) end 199 return function()
200 local ret, a, b = coroutine.resume(co)
201 if ret then return a, b
202 else return nil, a end
203 end
202end 204end
203 205
204--------------------------------------------------------------------------- 206---------------------------------------------------------------------------
205-- High level SMTP API 207-- High level SMTP API
206----------------------------------------------------------------------------- 208-----------------------------------------------------------------------------
207send = socket.protect(function(mailt) 209send = socket.protect(function(mailt)
208 local smtp = socket.try(open(mailt.server, mailt.port)) 210 local con = open(mailt.server, mailt.port)
209 smtp:greet(mailt.domain) 211 con:greet(mailt.domain)
210 smtp:send(mailt) 212 con:send(mailt)
211 smtp:quit() 213 con:quit()
212 return smtp:close() 214 return con:close()
213end) 215end)
214 216
215return smtp 217return smtp
diff --git a/src/socket.lua b/src/socket.lua
index 418cd1b..9aa6437 100644
--- a/src/socket.lua
+++ b/src/socket.lua
@@ -7,8 +7,8 @@
7----------------------------------------------------------------------------- 7-----------------------------------------------------------------------------
8-- Load LuaSocket from dynamic library 8-- Load LuaSocket from dynamic library
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10local open = assert(loadlib("luasocket", "luaopen_socket")) 10local socket = requirelib("luasocket", "luaopen_socket", getfenv(1))
11local socket = assert(open()) 11_LOADED["socket"] = socket
12 12
13----------------------------------------------------------------------------- 13-----------------------------------------------------------------------------
14-- Auxiliar functions 14-- Auxiliar functions
@@ -116,18 +116,21 @@ socket.sourcet["by-length"] = function(sock, length)
116end 116end
117 117
118socket.sourcet["until-closed"] = function(sock) 118socket.sourcet["until-closed"] = function(sock)
119 local done
119 return setmetatable({ 120 return setmetatable({
120 getfd = function() return sock:getfd() end, 121 getfd = function() return sock:getfd() end,
121 dirty = function() return sock:dirty() end 122 dirty = function() return sock:dirty() end
122 }, { 123 }, {
123 __call = ltn12.source.simplify(function() 124 __call = function()
125 if done then return nil end
124 local chunk, err, partial = sock:receive(socket.BLOCKSIZE) 126 local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
125 if not err then return chunk 127 if not err then return chunk
126 elseif err == "closed" then 128 elseif err == "closed" then
127 sock:close() 129 sock:close()
128 return partial, ltn12.source.empty() 130 done = 1
131 return partial
129 else return nil, err end 132 else return nil, err end
130 end) 133 end
131 }) 134 })
132end 135end
133 136
diff --git a/src/tcp.c b/src/tcp.c
index 90cfcde..845e0a3 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -9,13 +9,10 @@
9#include <lua.h> 9#include <lua.h>
10#include <lauxlib.h> 10#include <lauxlib.h>
11 11
12#include "luasocket.h"
13
14#include "auxiliar.h" 12#include "auxiliar.h"
15#include "socket.h" 13#include "socket.h"
16#include "inet.h" 14#include "inet.h"
17#include "options.h" 15#include "options.h"
18#include "base.h"
19#include "tcp.h" 16#include "tcp.h"
20 17
21/*=========================================================================*\ 18/*=========================================================================*\
@@ -41,7 +38,7 @@ static int meth_dirty(lua_State *L);
41/* tcp object methods */ 38/* tcp object methods */
42static luaL_reg tcp[] = { 39static luaL_reg tcp[] = {
43 {"__gc", meth_close}, 40 {"__gc", meth_close},
44 {"__tostring", base_meth_tostring}, 41 {"__tostring", aux_tostring},
45 {"accept", meth_accept}, 42 {"accept", meth_accept},
46 {"bind", meth_bind}, 43 {"bind", meth_bind},
47 {"close", meth_close}, 44 {"close", meth_close},
diff --git a/src/timeout.c b/src/timeout.c
index bd6c3b4..4f9a315 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -26,6 +26,14 @@
26#endif 26#endif
27#endif 27#endif
28 28
29/* min and max macros */
30#ifndef MIN
31#define MIN(x, y) ((x) < (y) ? x : y)
32#endif
33#ifndef MAX
34#define MAX(x, y) ((x) > (y) ? x : y)
35#endif
36
29/*=========================================================================*\ 37/*=========================================================================*\
30* Internal function prototypes 38* Internal function prototypes
31\*=========================================================================*/ 39\*=========================================================================*/
diff --git a/src/tp.lua b/src/tp.lua
index 3e9dba6..56dd8bc 100644
--- a/src/tp.lua
+++ b/src/tp.lua
@@ -2,24 +2,28 @@
2-- Unified SMTP/FTP subsystem 2-- Unified SMTP/FTP subsystem
3-- LuaSocket toolkit. 3-- LuaSocket toolkit.
4-- Author: Diego Nehab 4-- Author: Diego Nehab
5-- Conforming to: RFC 2616, LTN7
6-- RCS ID: $Id$ 5-- RCS ID: $Id$
7----------------------------------------------------------------------------- 6-----------------------------------------------------------------------------
8 7
9----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
10-- Load other required modules 9-- Load required modules
11----------------------------------------------------------------------------- 10-----------------------------------------------------------------------------
12local socket = require("socket") 11local socket = require("socket")
12local ltn12 = require("ltn12")
13 13
14----------------------------------------------------------------------------- 14-----------------------------------------------------------------------------
15-- Setup namespace 15-- Setup namespace
16----------------------------------------------------------------------------- 16-----------------------------------------------------------------------------
17tp = {} 17_LOADED["tp"] = getfenv(1)
18setmetatable(tp, { __index = _G })
19setfenv(1, tp)
20 18
19-----------------------------------------------------------------------------
20-- Program constants
21-----------------------------------------------------------------------------
21TIMEOUT = 60 22TIMEOUT = 60
22 23
24-----------------------------------------------------------------------------
25-- Implementation
26-----------------------------------------------------------------------------
23-- gets server reply (works for SMTP and FTP) 27-- gets server reply (works for SMTP and FTP)
24local function get_reply(control) 28local function get_reply(control)
25 local code, current, sep 29 local code, current, sep
@@ -37,7 +41,6 @@ local function get_reply(control)
37 -- reply ends with same code 41 -- reply ends with same code
38 until code == current and sep == " " 42 until code == current and sep == " "
39 end 43 end
40print(reply)
41 return code, reply 44 return code, reply
42end 45end
43 46
@@ -46,6 +49,7 @@ local metat = { __index = {} }
46 49
47function metat.__index:check(ok) 50function metat.__index:check(ok)
48 local code, reply = get_reply(self.control) 51 local code, reply = get_reply(self.control)
52print(reply)
49 if not code then return nil, reply end 53 if not code then return nil, reply end
50 if type(ok) ~= "function" then 54 if type(ok) ~= "function" then
51 if type(ok) == "table" then 55 if type(ok) == "table" then
@@ -103,11 +107,11 @@ function metat.__index:close()
103end 107end
104 108
105-- connect with server and return control object 109-- connect with server and return control object
106function connect(host, port) 110connect = socket.protect(function(host, port, timeout)
107 local control, err = socket.connect(host, port) 111 local control = socket.try(socket.tcp())
108 if not control then return nil, err end 112 socket.try(control:settimeout(timeout or TIMEOUT))
109 control:settimeout(TIMEOUT) 113 socket.try(control:connect(host, port))
110 return setmetatable({control = control}, metat) 114 return setmetatable({control = control}, metat)
111end 115end)
112 116
113return tp 117return tp
diff --git a/src/udp.c b/src/udp.c
index 4770a2e..51d6402 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -9,13 +9,10 @@
9#include <lua.h> 9#include <lua.h>
10#include <lauxlib.h> 10#include <lauxlib.h>
11 11
12#include "luasocket.h"
13
14#include "auxiliar.h" 12#include "auxiliar.h"
15#include "socket.h" 13#include "socket.h"
16#include "inet.h" 14#include "inet.h"
17#include "options.h" 15#include "options.h"
18#include "base.h"
19#include "udp.h" 16#include "udp.h"
20 17
21/*=========================================================================*\ 18/*=========================================================================*\
@@ -51,7 +48,7 @@ static luaL_reg udp[] = {
51 {"close", meth_close}, 48 {"close", meth_close},
52 {"setoption", meth_setoption}, 49 {"setoption", meth_setoption},
53 {"__gc", meth_close}, 50 {"__gc", meth_close},
54 {"__tostring", base_meth_tostring}, 51 {"__tostring", aux_tostring},
55 {"getfd", meth_getfd}, 52 {"getfd", meth_getfd},
56 {"setfd", meth_setfd}, 53 {"setfd", meth_setfd},
57 {"dirty", meth_dirty}, 54 {"dirty", meth_dirty},
diff --git a/src/url.lua b/src/url.lua
index 2441268..aac2a47 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -9,9 +9,7 @@
9----------------------------------------------------------------------------- 9-----------------------------------------------------------------------------
10-- Setup namespace 10-- Setup namespace
11----------------------------------------------------------------------------- 11-----------------------------------------------------------------------------
12local url = {} 12_LOADED["url"] = getfenv(1)
13setmetatable(url, { __index = _G })
14setfenv(1, url)
15 13
16----------------------------------------------------------------------------- 14-----------------------------------------------------------------------------
17-- Encodes a string into its escaped hexadecimal representation 15-- Encodes a string into its escaped hexadecimal representation