diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/auxiliar.c | 50 | ||||
| -rw-r--r-- | src/auxiliar.h | 25 | ||||
| -rw-r--r-- | src/buffer.c | 9 | ||||
| -rw-r--r-- | src/except.c | 52 | ||||
| -rw-r--r-- | src/except.h | 35 | ||||
| -rw-r--r-- | src/ftp.lua | 73 | ||||
| -rw-r--r-- | src/http.lua | 351 | ||||
| -rw-r--r-- | src/inet.c | 1 | ||||
| -rw-r--r-- | src/ltn12.lua | 21 | ||||
| -rw-r--r-- | src/luasocket.c | 71 | ||||
| -rw-r--r-- | src/luasocket.h | 1 | ||||
| -rw-r--r-- | src/mime.c | 12 | ||||
| -rw-r--r-- | src/mime.h | 1 | ||||
| -rw-r--r-- | src/mime.lua | 14 | ||||
| -rw-r--r-- | src/select.c | 221 | ||||
| -rw-r--r-- | src/smtp.lua | 50 | ||||
| -rw-r--r-- | src/socket.lua | 13 | ||||
| -rw-r--r-- | src/tcp.c | 5 | ||||
| -rw-r--r-- | src/timeout.c | 8 | ||||
| -rw-r--r-- | src/tp.lua | 26 | ||||
| -rw-r--r-- | src/udp.c | 5 | ||||
| -rw-r--r-- | src/url.lua | 4 |
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 | \*-------------------------------------------------------------------------*/ |
| 19 | int aux_open(lua_State *L) | 18 | int 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 | \*-------------------------------------------------------------------------*/ |
| 27 | void aux_newclass(lua_State *L, const char *classname, luaL_reg *func) | 26 | void 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 | \*-------------------------------------------------------------------------*/ | ||
| 49 | int 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; | ||
| 61 | error: | ||
| 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 | \*-------------------------------------------------------------------------*/ |
| 51 | void aux_add2group(lua_State *L, const char *classname, const char *groupname) | 70 | void 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 | \*-------------------------------------------------------------------------*/ |
| 63 | int aux_checkboolean(lua_State *L, int objidx) | 81 | int 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 | \*-------------------------------------------------------------------------*/ |
| 74 | void *aux_checkclass(lua_State *L, const char *classname, int objidx) | 91 | void *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 | \*-------------------------------------------------------------------------*/ |
| 89 | void *aux_checkgroup(lua_State *L, const char *groupname, int objidx) | 105 | void *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 | \*-------------------------------------------------------------------------*/ |
| 103 | void aux_setclass(lua_State *L, const char *classname, int objidx) | 118 | void 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 | \*-------------------------------------------------------------------------*/ |
| 114 | void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx) | 128 | void *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 | \*-------------------------------------------------------------------------*/ |
| 133 | void *aux_getclassudata(lua_State *L, const char *classname, int objidx) | 146 | void *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 | |||
| 43 | int aux_open(lua_State *L); | 37 | int aux_open(lua_State *L); |
| 44 | void aux_newclass(lua_State *L, const char *classname, luaL_reg *func); | 38 | void aux_newclass(lua_State *L, const char *classname, luaL_reg *func); |
| 45 | void aux_add2group(lua_State *L, const char *classname, const char *group); | 39 | void 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); | |||
| 49 | void *aux_getclassudata(lua_State *L, const char *groupname, int objidx); | 43 | void *aux_getclassudata(lua_State *L, const char *groupname, int objidx); |
| 50 | void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx); | 44 | void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx); |
| 51 | int aux_checkboolean(lua_State *L, int objidx); | 45 | int aux_checkboolean(lua_State *L, int objidx); |
| 46 | int 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); | |||
| 20 | static void buf_skip(p_buf buf, size_t count); | 19 | static void buf_skip(p_buf buf, size_t count); |
| 21 | static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent); | 20 | static 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 | |||
| 6 | static int global_try(lua_State *L); | ||
| 7 | static int global_protect(lua_State *L); | ||
| 8 | static int protected(lua_State *L); | ||
| 9 | |||
| 10 | static luaL_reg func[] = { | ||
| 11 | {"try", global_try}, | ||
| 12 | {"protect", global_protect}, | ||
| 13 | {NULL, NULL} | ||
| 14 | }; | ||
| 15 | |||
| 16 | /*-------------------------------------------------------------------------*\ | ||
| 17 | * Exception handling: try method | ||
| 18 | \*-------------------------------------------------------------------------*/ | ||
| 19 | static 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 | \*-------------------------------------------------------------------------*/ | ||
| 30 | static 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 | |||
| 40 | static 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 | \*-------------------------------------------------------------------------*/ | ||
| 49 | int 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 | |||
| 33 | int 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 | ----------------------------------------------------------------------------- |
| 12 | local socket = require("socket") | 12 | local socket = require("socket") |
| 13 | local ltn12 = require("ltn12") | 13 | local ltn12 = require("ltn12") |
| @@ -17,10 +17,7 @@ local tp = require("tp") | |||
| 17 | ----------------------------------------------------------------------------- | 17 | ----------------------------------------------------------------------------- |
| 18 | -- Setup namespace | 18 | -- Setup namespace |
| 19 | ----------------------------------------------------------------------------- | 19 | ----------------------------------------------------------------------------- |
| 20 | local ftp = {} | 20 | _LOADED["ftp"] = getfenv(1) |
| 21 | -- make all module globals fall into namespace | ||
| 22 | setmetatable(ftp, { __index = _G }) | ||
| 23 | setfenv(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. |
| 34 | USER = "ftp" | 31 | USER = "ftp" |
| 35 | EMAIL = "anonymous@anonymous.org" | 32 | PASSWORD = "anonymous@anonymous.org" |
| 36 | -- block size used in transfers | ||
| 37 | BLOCKSIZE = 2048 | ||
| 38 | 33 | ||
| 39 | ----------------------------------------------------------------------------- | 34 | ----------------------------------------------------------------------------- |
| 40 | -- Low level FTP API | 35 | -- Low level FTP API |
| @@ -42,7 +37,7 @@ BLOCKSIZE = 2048 | |||
| 42 | local metat = { __index = {} } | 37 | local metat = { __index = {} } |
| 43 | 38 | ||
| 44 | function open(server, port) | 39 | function 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) |
| 47 | end | 42 | end |
| 48 | 43 | ||
| @@ -51,14 +46,17 @@ local function port(portt) | |||
| 51 | end | 46 | end |
| 52 | 47 | ||
| 53 | local function pasv(pasvt) | 48 | local 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 | ||
| 55 | end | 53 | end |
| 56 | 54 | ||
| 57 | function metat.__index:login(user, password) | 55 | function 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 | ----------------------------------------------------------------------------- |
| 184 | local function tput(putt) | 184 | local 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() |
| 193 | end | 193 | end |
| 194 | 194 | ||
| 195 | local default = { | 195 | local default = { |
| @@ -198,15 +198,16 @@ local default = { | |||
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | local function parse(u) | 200 | local 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 |
| 210 | end | 211 | end |
| 211 | 212 | ||
| 212 | local function sput(u, body) | 213 | local function sput(u, body) |
| @@ -221,17 +222,17 @@ put = socket.protect(function(putt, body) | |||
| 221 | end) | 222 | end) |
| 222 | 223 | ||
| 223 | local function tget(gett) | 224 | local 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() |
| 232 | end | 233 | end |
| 233 | 234 | ||
| 234 | local function sget(u, body) | 235 | local 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) | |||
| 240 | end | 241 | end |
| 241 | 242 | ||
| 242 | get = socket.protect(function(gett) | 243 | get = 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 |
| 245 | end) | 246 | end) |
| 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 | ------------------------------------------------------------------------------- |
| 12 | local socket = require("socket") | 12 | local socket = require("socket") |
| 13 | local ltn12 = require("ltn12") | 13 | local ltn12 = require("ltn12") |
| @@ -17,42 +17,68 @@ local url = require("url") | |||
| 17 | ----------------------------------------------------------------------------- | 17 | ----------------------------------------------------------------------------- |
| 18 | -- Setup namespace | 18 | -- Setup namespace |
| 19 | ------------------------------------------------------------------------------- | 19 | ------------------------------------------------------------------------------- |
| 20 | http = {} | 20 | _LOADED["http"] = getfenv(1) |
| 21 | -- make all module globals fall into namespace | ||
| 22 | setmetatable(http, { __index = _G }) | ||
| 23 | setfenv(1, http) | ||
| 24 | 21 | ||
| 25 | ----------------------------------------------------------------------------- | 22 | ----------------------------------------------------------------------------- |
| 26 | -- Program constants | 23 | -- Program constants |
| 27 | ----------------------------------------------------------------------------- | 24 | ----------------------------------------------------------------------------- |
| 28 | -- connection timeout in seconds | 25 | -- connection timeout in seconds |
| 29 | TIMEOUT = 60 | 26 | TIMEOUT = 4 |
| 30 | -- default port for document retrieval | 27 | -- default port for document retrieval |
| 31 | PORT = 80 | 28 | PORT = 80 |
| 32 | -- user agent field sent in request | 29 | -- user agent field sent in request |
| 33 | USERAGENT = socket.version | 30 | USERAGENT = socket.VERSION |
| 34 | -- block size used in transfers | 31 | -- block size used in transfers |
| 35 | BLOCKSIZE = 2048 | 32 | BLOCKSIZE = 2048 |
| 36 | 33 | ||
| 37 | ----------------------------------------------------------------------------- | 34 | ----------------------------------------------------------------------------- |
| 38 | -- Function return value selectors | 35 | -- Low level HTTP API |
| 39 | ----------------------------------------------------------------------------- | 36 | ----------------------------------------------------------------------------- |
| 40 | local function second(a, b) | 37 | local metat = { __index = {} } |
| 41 | return b | 38 | |
| 39 | function 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) | ||
| 45 | end | ||
| 46 | |||
| 47 | function 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)) | ||
| 42 | end | 50 | end |
| 43 | 51 | ||
| 44 | local function third(a, b, c) | 52 | function 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 | ||
| 46 | end | 59 | end |
| 47 | 60 | ||
| 48 | local function receive_headers(reqt, respt, tmp) | 61 | function 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)) | ||
| 69 | end | ||
| 70 | |||
| 71 | function 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) | ||
| 75 | end | ||
| 76 | |||
| 77 | function 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 | ||
| 73 | end | 100 | end |
| 74 | 101 | ||
| 75 | local function receive_body(reqt, respt, tmp) | 102 | function 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)) | ||
| 92 | end | 113 | end |
| 93 | 114 | ||
| 94 | local function send_headers(sock, headers) | 115 | function 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")) | ||
| 101 | end | 117 | end |
| 102 | 118 | ||
| 103 | local 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 | 122 | local function uri(reqt) |
| 107 | return 1 | 123 | local u = reqt |
| 108 | end | 124 | if not reqt.proxy and not PROXY then |
| 109 | 125 | u = { | |
| 110 | local 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 | ||
| 115 | end | ||
| 116 | |||
| 117 | local 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) |
| 129 | end | 133 | end |
| 130 | 134 | ||
| 131 | local function send_request(reqt, respt, tmp) | 135 | local 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 | ||
| 151 | end | ||
| 152 | |||
| 153 | local 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)) | ||
| 167 | end | ||
| 168 | |||
| 169 | local 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 | ||
| 181 | end | 145 | end |
| 182 | 146 | ||
| 183 | local function parse_url(reqt, respt, tmp) | 147 | local 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 | ||
| 199 | end | 162 | end |
| 200 | 163 | ||
| 201 | -- forward declaration | 164 | local function shouldredirect(reqt, respt) |
| 202 | local 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) | ||
| 169 | end | ||
| 203 | 170 | ||
| 204 | local function should_authorize(reqt, respt, tmp) | 171 | local 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 |
| 210 | end | 177 | end |
| 211 | 178 | ||
| 212 | local function clone(headers) | 179 | local 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 | ||
| 219 | end | 185 | end |
| 220 | 186 | ||
| 221 | local function authorize(reqt, respt, tmp) | 187 | local requestp, authorizep, redirectp |
| 222 | local headers = clone(reqt.headers) or {} | 188 | |
| 223 | headers["authorization"] = "Basic " .. | 189 | function 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 | ||
| 235 | end | 209 | end |
| 236 | 210 | ||
| 237 | local function should_redirect(reqt, respt, tmp) | 211 | function 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) | ||
| 242 | end | 215 | end |
| 243 | 216 | ||
| 244 | local function redirect(reqt, respt, tmp) | 217 | function 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 |
| 260 | end | ||
| 261 | |||
| 262 | local function skip_continue(reqt, respt, tmp) | ||
| 263 | if respt.code == 100 then | ||
| 264 | receive_status(reqt, respt, tmp) | ||
| 265 | end | ||
| 266 | end | ||
| 267 | |||
| 268 | -- execute a request of through an exception | ||
| 269 | function 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 | ||
| 286 | end | ||
| 287 | |||
| 288 | function 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 |
| 294 | end | 235 | end |
| 295 | 236 | ||
| 296 | function get(u) | 237 | request = socket.protect(requestp) |
| 238 | |||
| 239 | get = 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 |
| 304 | end | 247 | end) |
| 305 | 248 | ||
| 306 | function post(u, body) | 249 | post = 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 |
| 317 | end | 260 | end) |
| 318 | 261 | ||
| 319 | return http | 262 | return http |
| @@ -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 | ----------------------------------------------------------------------------- |
| 11 | local ltn12 = {} | 11 | _LOADED["ltn12"] = getfenv(1) |
| 12 | setmetatable(ltn12, { __index = _G }) | 12 | |
| 13 | setfenv(1, ltn12) | ||
| 14 | filter = {} | 13 | filter = {} |
| 15 | source = {} | 14 | source = {} |
| 16 | sink = {} | 15 | sink = {} |
| @@ -19,10 +18,6 @@ pump = {} | |||
| 19 | -- 2048 seems to be better in windows... | 18 | -- 2048 seems to be better in windows... |
| 20 | BLOCKSIZE = 2048 | 19 | BLOCKSIZE = 2048 |
| 21 | 20 | ||
| 22 | local function shift(a, b, c) | ||
| 23 | return b, c | ||
| 24 | end | ||
| 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 |
| 58 | end | 55 | end |
| 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 |
| 154 | end | 153 | end |
| 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 |
| 171 | end | 172 | end |
| 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 | \*-------------------------------------------------------------------------*/ | ||
| 40 | static int global_skip(lua_State *L); | ||
| 41 | static int global_unload(lua_State *L); | ||
| 42 | static int base_open(lua_State *L); | ||
| 43 | |||
| 44 | /*-------------------------------------------------------------------------*\ | ||
| 45 | * Modules and functions | ||
| 39 | \*-------------------------------------------------------------------------*/ | 46 | \*-------------------------------------------------------------------------*/ |
| 40 | static const luaL_reg mod[] = { | 47 | static 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 | ||
| 59 | static luaL_reg func[] = { | ||
| 60 | {"skip", global_skip}, | ||
| 61 | {"__unload", global_unload}, | ||
| 62 | {NULL, NULL} | ||
| 63 | }; | ||
| 64 | |||
| 65 | /*-------------------------------------------------------------------------*\ | ||
| 66 | * Skip a few arguments | ||
| 67 | \*-------------------------------------------------------------------------*/ | ||
| 68 | static 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 | \*-------------------------------------------------------------------------*/ | ||
| 77 | static int global_unload(lua_State *L) { | ||
| 78 | sock_close(); | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | /*-------------------------------------------------------------------------*\ | ||
| 83 | * Setup basic stuff. | ||
| 84 | \*-------------------------------------------------------------------------*/ | ||
| 85 | static 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 | \*-------------------------------------------------------------------------*/ |
| 55 | LUASOCKET_API int luaopen_socket(lua_State *L) { | 119 | LUASOCKET_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" | ||
| 28 | LUASOCKET_API int luaopen_socket(lua_State *L); | 29 | LUASOCKET_API int luaopen_socket(lua_State *L); |
| 29 | 30 | ||
| 30 | #endif /* LUASOCKET_H */ | 31 | #endif /* LUASOCKET_H */ |
| @@ -76,7 +76,17 @@ static UC b64unbase[256]; | |||
| 76 | \*-------------------------------------------------------------------------*/ | 76 | \*-------------------------------------------------------------------------*/ |
| 77 | MIME_API int luaopen_mime(lua_State *L) | 77 | MIME_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); |
| @@ -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" | ||
| 22 | MIME_API int luaopen_mime(lua_State *L); | 23 | MIME_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 | ----------------------------------------------------------------------------- | ||
| 12 | local open = assert(loadlib("mime", "luaopen_mime")) | ||
| 13 | local mime = assert(open()) | ||
| 14 | |||
| 15 | ----------------------------------------------------------------------------- | ||
| 16 | -- Load other required modules | 9 | -- Load other required modules |
| 17 | ----------------------------------------------------------------------------- | 10 | ----------------------------------------------------------------------------- |
| 11 | local mime = requirelib("mime", "luaopen_mime", getfenv(1)) | ||
| 18 | local ltn12 = require("ltn12") | 12 | local 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 |
| 24 | setmetatable(mime, { __index = _G }) | ||
| 25 | setfenv(1, mime) | ||
| 26 | 18 | ||
| 27 | -- encode, decode and wrap algorithm tables | 19 | -- encode, decode and wrap algorithm tables |
| 28 | encodet = {} | 20 | encodet = {} |
| @@ -48,7 +40,7 @@ end | |||
| 48 | 40 | ||
| 49 | encodet['quoted-printable'] = function(mode) | 41 | encodet['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") |
| 52 | end | 44 | end |
| 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 | \*=========================================================================*/ |
| 20 | static int meth_set(lua_State *L); | 18 | static int getfd(lua_State *L); |
| 21 | static int meth_isset(lua_State *L); | 19 | static int dirty(lua_State *L); |
| 22 | static int c_select(lua_State *L); | 20 | static int collect_fd(lua_State *L, int tab, int max_fd, int itab, fd_set *set); |
| 21 | static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set); | ||
| 22 | static void return_fd(lua_State *L, fd_set *set, int max_fd, | ||
| 23 | int itab, int tab, int start); | ||
| 24 | static void make_assoc(lua_State *L, int tab); | ||
| 23 | static int global_select(lua_State *L); | 25 | static int global_select(lua_State *L); |
| 24 | 26 | ||
| 25 | /* fd_set object methods */ | ||
| 26 | static 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 */ |
| 33 | static luaL_reg func[] = { | 28 | static 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 | \*-------------------------------------------------------------------------*/ |
| 44 | int select_open(lua_State *L) | 39 | int 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 | \*-------------------------------------------------------------------------*/ |
| 64 | static int global_select(lua_State *L) | 50 | static 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 | \*=========================================================================*/ |
| 92 | static int meth_set(lua_State *L) | 84 | static 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 | ||
| 100 | static int meth_isset(lua_State *L) | 98 | static 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 | /*=========================================================================*\ | 111 | static 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; |
| 112 | static 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 | |||
| 138 | static 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 | |||
| 163 | static 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 | |||
| 176 | static 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 | ----------------------------------------------------------------------------- | ||
| 13 | local open = assert(loadlib("smtp", "luaopen_smtp")) | ||
| 14 | local smtp = assert(open()) | ||
| 15 | |||
| 16 | ----------------------------------------------------------------------------- | ||
| 17 | -- Load other required modules | ||
| 18 | ----------------------------------------------------------------------------- | 11 | ----------------------------------------------------------------------------- |
| 12 | local smtp = requirelib("smtp") | ||
| 19 | local socket = require("socket") | 13 | local socket = require("socket") |
| 20 | local ltn12 = require("ltn12") | 14 | local ltn12 = require("ltn12") |
| 21 | local tp = require("tp") | 15 | local 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 |
| 27 | setmetatable(smtp, { __index = _G }) | ||
| 28 | setfenv(1, smtp) | ||
| 29 | 21 | ||
| 22 | -- timeout for connection | ||
| 23 | TIMEOUT = 60 | ||
| 30 | -- default server used to send e-mails | 24 | -- default server used to send e-mails |
| 31 | SERVER = "localhost" | 25 | SERVER = "localhost" |
| 32 | -- default port | 26 | -- default port |
| @@ -94,9 +88,7 @@ function metat.__index:send(mailt) | |||
| 94 | end | 88 | end |
| 95 | 89 | ||
| 96 | function open(server, port) | 90 | function 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) |
| 101 | end | 93 | end |
| 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 | ||
| 134 | end | 132 | end |
| 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 |
| 184 | local function adjust_headers(mesgt) | 182 | local 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 | ||
| 202 | end | 204 | end |
| 203 | 205 | ||
| 204 | --------------------------------------------------------------------------- | 206 | --------------------------------------------------------------------------- |
| 205 | -- High level SMTP API | 207 | -- High level SMTP API |
| 206 | ----------------------------------------------------------------------------- | 208 | ----------------------------------------------------------------------------- |
| 207 | send = socket.protect(function(mailt) | 209 | send = 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() |
| 213 | end) | 215 | end) |
| 214 | 216 | ||
| 215 | return smtp | 217 | return 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 | ----------------------------------------------------------------------------- |
| 10 | local open = assert(loadlib("luasocket", "luaopen_socket")) | 10 | local socket = requirelib("luasocket", "luaopen_socket", getfenv(1)) |
| 11 | local 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) | |||
| 116 | end | 116 | end |
| 117 | 117 | ||
| 118 | socket.sourcet["until-closed"] = function(sock) | 118 | socket.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 | }) |
| 132 | end | 135 | end |
| 133 | 136 | ||
| @@ -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 */ |
| 42 | static luaL_reg tcp[] = { | 39 | static 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 | \*=========================================================================*/ |
| @@ -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 | ----------------------------------------------------------------------------- |
| 12 | local socket = require("socket") | 11 | local socket = require("socket") |
| 12 | local ltn12 = require("ltn12") | ||
| 13 | 13 | ||
| 14 | ----------------------------------------------------------------------------- | 14 | ----------------------------------------------------------------------------- |
| 15 | -- Setup namespace | 15 | -- Setup namespace |
| 16 | ----------------------------------------------------------------------------- | 16 | ----------------------------------------------------------------------------- |
| 17 | tp = {} | 17 | _LOADED["tp"] = getfenv(1) |
| 18 | setmetatable(tp, { __index = _G }) | ||
| 19 | setfenv(1, tp) | ||
| 20 | 18 | ||
| 19 | ----------------------------------------------------------------------------- | ||
| 20 | -- Program constants | ||
| 21 | ----------------------------------------------------------------------------- | ||
| 21 | TIMEOUT = 60 | 22 | TIMEOUT = 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) |
| 24 | local function get_reply(control) | 28 | local 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 |
| 40 | print(reply) | ||
| 41 | return code, reply | 44 | return code, reply |
| 42 | end | 45 | end |
| 43 | 46 | ||
| @@ -46,6 +49,7 @@ local metat = { __index = {} } | |||
| 46 | 49 | ||
| 47 | function metat.__index:check(ok) | 50 | function metat.__index:check(ok) |
| 48 | local code, reply = get_reply(self.control) | 51 | local code, reply = get_reply(self.control) |
| 52 | print(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() | |||
| 103 | end | 107 | end |
| 104 | 108 | ||
| 105 | -- connect with server and return control object | 109 | -- connect with server and return control object |
| 106 | function connect(host, port) | 110 | connect = 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) |
| 111 | end | 115 | end) |
| 112 | 116 | ||
| 113 | return tp | 117 | return tp |
| @@ -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 | ----------------------------------------------------------------------------- |
| 12 | local url = {} | 12 | _LOADED["url"] = getfenv(1) |
| 13 | setmetatable(url, { __index = _G }) | ||
| 14 | setfenv(1, url) | ||
| 15 | 13 | ||
| 16 | ----------------------------------------------------------------------------- | 14 | ----------------------------------------------------------------------------- |
| 17 | -- Encodes a string into its escaped hexadecimal representation | 15 | -- Encodes a string into its escaped hexadecimal representation |
