diff --git a/TODO b/TODO index 4b475ae..260d9bf 100644 --- a/TODO +++ b/TODO @@ -1,48 +1,37 @@ +manual + add shutdown + add gethostname + the need of a content-length header in the post method... + notice the change in callback conventions + the callback.lua module and the new mime module. + escape and unescape in url, not in code! + add timeout and proxy to request table + change stay to redirect + socket.time and socket.sleep + connect with timeout + local connect + add thanks to 'carlos cassino' and 'david burgess' + add new ip- options and reuseaddr option -comment the need of a content-length header in the post method... - -comment the callback.lua module and the new mime module. - escape and unescape are missing! +tests + checar todos os metodos + checar todas as globais + checar garbage collection + check for interrupts +new option.c module to put all options (TCP and UDP share...)? +testar os options! add _tostring methods! -add callback module to manual -change stay to redirect in http.lua and in manual -add timeout to request table - -change code to mime -change *all* modules to be namespace independent +change all modules to use the new namespace scheme write some utilities that use the code.lua module and put them in etc, modify the README.etc file and makefile.dist (eol.lua is done) -check for interrupt compliance -add connect with timeout -add gethostname and use it in HTTP, SMTP etc, and add manual entry. -add thanks for cassino and david burgess - -add local connect, and manual entry - -add shutdown manual entry - -only allocate in case of success -only call select if io fails... -Proxy support pro http - -make REUSEADDR an option... +use gethostname it in SMTP make sure modules know if their dependencies are there. -_ -one thing i noticed in usocket.c is that it doesn't check for EINTR -after write(), sendto(), read(), recvfrom() etc. ? the usual trick is -to loop while you get EINTR: - - do - ret = write(...); - while(ret < 0 && errno == EINTR) - Read about - 250-ENHANCEDSTATUSCODES 250-PIPELINING 250-8BITMIME @@ -62,29 +51,30 @@ Make sure nobody can fuck up with the metatables... Create a passive mode option for the FTP (good for firewall). -Use environments in module definitions or declare all local and create the -function with exported symbols later? - -local P = {} -complex = P -setfenv(1, P) - Modules should return their namespace table in the end of the chunk. Adjust dates in all files Test the library on every system possible -Document socket.time and socket.sleep - -Implement time critical stuff from code module in C. Add service name translation. - Ajeitar o protocolo da luaopen_socket()... sei lá qual é. -- testar os options! + - adicionar exemplos de expansão: pipe, local, named pipe +* should be interrupt-safe +* notice the change in callback conventions +* new mime module replacing old code module (faster, more functionality) +* new socket options (many) +* only allocate in case of success +* optimize for success (only call select if fails) +* add proxy support to http +* add gethostname +* local connect +* connect with timeout +* change code to mime +* change stay to redirect * add shutdown * change send/recv to avoid using select * O location do "redirect" pode ser relativo ao servidor atual (não pode, @@ -93,24 +83,13 @@ Ajeitar o protocolo da luaopen_socket()... sei l * Padronizar os retornos de funccao * Separar as classes em arquivos * Retorno de sendto em datagram sockets pode ser refused -* Fazer compilar com g++ +- Fazer compilar com g++ - Thread-safe - proteger gethostby*.* com um mutex GLOBAL! - proteger ou atomizar o conjunto (timedout, receive), (timedout, send) - inet_ntoa também é uma merda. - SSL -- checar operações em closed sockets -- checar teste de writable socket com select - - -- checar todos os metodos -- checar options em UDP -- checar todas as globais -- checar os metodos virtuais -- checar garbage collection - - unix 92 bytes maximo no endereço, incluindo o zero - unix 9216 maximo de datagram size - diff --git a/src/auxiliar.c b/src/auxiliar.c index 65425c5..4b3a0f6 100644 --- a/src/auxiliar.c +++ b/src/auxiliar.c @@ -17,24 +17,7 @@ \*-------------------------------------------------------------------------*/ void aux_open(lua_State *L) { - /* create namespace table */ - lua_pushstring(L, LUASOCKET_LIBNAME); - lua_newtable(L); -#ifdef LUASOCKET_DEBUG - lua_pushstring(L, "debug"); - lua_pushnumber(L, 1); - lua_rawset(L, -3); -#endif - /* make version string available so scripts */ - lua_pushstring(L, "version"); - lua_pushstring(L, LUASOCKET_VERSION); - lua_rawset(L, -3); - /* store namespace as global */ - lua_settable(L, LUA_GLOBALSINDEX); - /* make sure modules know what is our namespace */ - lua_pushstring(L, "LUASOCKET_LIBNAME"); - lua_pushstring(L, LUASOCKET_LIBNAME); - lua_settable(L, LUA_GLOBALSINDEX); + ; } /*-------------------------------------------------------------------------*\ diff --git a/src/http.lua b/src/http.lua index 72bde0a..4d6e426 100644 --- a/src/http.lua +++ b/src/http.lua @@ -25,7 +25,7 @@ TIMEOUT = 60 -- default port for document retrieval PORT = 80 -- user agent field sent in request -USERAGENT = "LuaSocket 2.0" +USERAGENT = socket.version -- block size used in transfers BLOCKSIZE = 8192 @@ -429,8 +429,7 @@ local function authorize(reqt, parsed, respt) body_cb = reqt.body_cb, headers = reqt.headers, timeout = reqt.timeout, - proxyhost = reqt.proxyhost, - proxyport = reqt.proxyport + proxy = reqt.proxy, } return request_cb(autht, respt) end @@ -471,8 +470,7 @@ local function redirect(reqt, respt) body_cb = reqt.body_cb, headers = reqt.headers, timeout = reqt.timeout, - proxyhost = reqt.proxyhost, - proxyport = reqt.proxyport + proxy = reqt.proxy } respt = request_cb(redirt, respt) -- we pass the location header as a clue we tried to redirect @@ -491,7 +489,7 @@ end ----------------------------------------------------------------------------- local function request_uri(reqt, parsed) local url - if not reqt.proxyhost and not reqt.proxyport then + if not reqt.proxy then url = { path = parsed.path, params = parsed.params, @@ -522,6 +520,39 @@ local function build_request(data) return reqt end +----------------------------------------------------------------------------- +-- Connects to a server, be it a proxy or not +-- Input +-- reqt: the request table +-- parsed: the parsed request url +-- Returns +-- sock: connection socket, or nil in case of error +-- err: error message +----------------------------------------------------------------------------- +local function try_connect(reqt, parsed) + reqt.proxy = reqt.proxy or PROXY + local host, port + if reqt.proxy then + local pproxy = socket.url.parse(reqt.proxy) + if not pproxy.port or not pproxy.host then + return nil, "invalid proxy" + end + host, port = pproxy.host, pproxy.port + else + host, port = parsed.host, parsed.port + end + local sock, ret, err + sock, err = socket.tcp() + if not sock then return nil, err end + sock:settimeout(reqt.timeout or TIMEOUT) + ret, err = sock:connect(host, port) + if not ret then + sock:close() + return nil, err + end + return sock +end + ----------------------------------------------------------------------------- -- Sends a HTTP request and retrieves the server reply using callbacks to -- send the request body and receive the response body @@ -562,18 +593,8 @@ function request_cb(reqt, respt) -- fill default headers reqt.headers = fill_headers(reqt.headers, parsed) -- try to connect to server - sock, respt.error = socket.tcp() + sock, respt.error = try_connect(reqt, parsed) if not sock then return respt end - -- set connection timeout so that we do not hang forever - sock:settimeout(reqt.timeout or TIMEOUT) - ret, respt.error = sock:connect( - reqt.proxyhost or PROXYHOST or parsed.host, - reqt.proxyport or PROXYPORT or parsed.port - ) - if not ret then - sock:close() - return respt - end -- send request message respt.error = send_request(sock, reqt.method, request_uri(reqt, parsed), reqt.headers, reqt.body_cb) diff --git a/src/luasocket.c b/src/luasocket.c index 578d65c..73583a8 100644 --- a/src/luasocket.c +++ b/src/luasocket.c @@ -36,8 +36,63 @@ #include "mime.h" /*=========================================================================*\ -* Exported functions +* Declarations \*=========================================================================*/ +static int global_gethostname(lua_State *L); +static int base_open(lua_State *L); + +/* functions in library namespace */ +static luaL_reg func[] = { + {"gethostname", global_gethostname}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Setup basic stuff. +\*-------------------------------------------------------------------------*/ +static int base_open(lua_State *L) +{ + /* create namespace table */ + lua_pushstring(L, LUASOCKET_LIBNAME); + lua_newtable(L); +#ifdef LUASOCKET_DEBUG + lua_pushstring(L, "debug"); + lua_pushnumber(L, 1); + lua_rawset(L, -3); +#endif + /* make version string available so scripts */ + lua_pushstring(L, "version"); + lua_pushstring(L, LUASOCKET_VERSION); + lua_rawset(L, -3); + /* store namespace as global */ + lua_settable(L, LUA_GLOBALSINDEX); + /* make sure modules know what is our namespace */ + lua_pushstring(L, "LUASOCKET_LIBNAME"); + lua_pushstring(L, LUASOCKET_LIBNAME); + lua_settable(L, LUA_GLOBALSINDEX); + /* define library functions */ + luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); + lua_pop(L, 1); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Gets the host name +\*-------------------------------------------------------------------------*/ +static int global_gethostname(lua_State *L) +{ + char name[257]; + name[256] = '\0'; + if (gethostname(name, 256) < 0) { + lua_pushnil(L); + lua_pushstring(L, "gethostname failed"); + return 2; + } else { + lua_pushstring(L, name); + return 1; + } +} + /*-------------------------------------------------------------------------*\ * Initializes all library modules. \*-------------------------------------------------------------------------*/ @@ -45,6 +100,7 @@ LUASOCKET_API int luaopen_socket(lua_State *L) { if (!sock_open()) return 0; /* initialize all modules */ + base_open(L); aux_open(L); tm_open(L); buf_open(L); diff --git a/src/luasocket.h b/src/luasocket.h index ac26824..81d7b3f 100644 --- a/src/luasocket.h +++ b/src/luasocket.h @@ -13,7 +13,7 @@ /*-------------------------------------------------------------------------*\ * Current luasocket version \*-------------------------------------------------------------------------*/ -#define LUASOCKET_VERSION "LuaSocket 2.0 (alpha)" +#define LUASOCKET_VERSION "LuaSocket 2.0 (beta)" /*-------------------------------------------------------------------------*\ * Library's namespace diff --git a/src/tcp.c b/src/tcp.c index 21aa7f5..5505848 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -153,7 +153,7 @@ static int opt_keepalive(lua_State *L) return opt_boolean(L, SOL_SOCKET, SO_KEEPALIVE); } -int opt_linger(lua_State *L) +static int opt_linger(lua_State *L) { p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); struct linger li; @@ -334,7 +334,7 @@ static int meth_settimeout(lua_State *L) /*-------------------------------------------------------------------------*\ * Creates a master tcp object \*-------------------------------------------------------------------------*/ -int global_create(lua_State *L) +static int global_create(lua_State *L) { t_sock sock; const char *err = inet_trycreate(&sock, SOCK_STREAM); diff --git a/src/udp.c b/src/udp.c index c730206..c5e14d1 100644 --- a/src/udp.c +++ b/src/udp.c @@ -417,7 +417,7 @@ static int meth_setsockname(lua_State *L) /*-------------------------------------------------------------------------*\ * Creates a master udp object \*-------------------------------------------------------------------------*/ -int global_create(lua_State *L) +static int global_create(lua_State *L) { t_sock sock; const char *err = inet_trycreate(&sock, SOCK_DGRAM); diff --git a/test/httptest.lua b/test/httptest.lua index dc90741..44266d5 100644 --- a/test/httptest.lua +++ b/test/httptest.lua @@ -5,14 +5,15 @@ -- needs "AllowOverride AuthConfig" on /home/c/diego/tec/luasocket/test/auth dofile("noglobals.lua") -local host, proxyhost, proxyport, request, response +local host, proxy, request, response local ignore, expect, index, prefix, cgiprefix +socket.http.TIMEOUT = 5 + local t = socket.time() -host = host or "diego.princeton.edu" -proxyhost = proxyhost or "localhost" -proxyport = proxyport or 3128 +host = host or "diego.student.dyn.cs.princeton.edu" +proxy = proxy or "http://localhost:3128" prefix = prefix or "/luasocket-test" cgiprefix = cgiprefix or "/luasocket-test-cgi" @@ -66,6 +67,7 @@ end io.write("testing request uri correctness: ") local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string" local back, h, c, e = socket.http.get("http://" .. host .. forth) +if not back then fail(e) end back = socket.url.parse(back) if similar(back.query, "this+is+the+query+string") then print("ok") else fail() end @@ -129,8 +131,7 @@ request = { method = "POST", body = index, headers = { ["content-length"] = string.len(index) }, - proxyport = proxyport, - proxyhost = proxyhost + proxy= proxy } expect = { body = index, @@ -170,8 +171,7 @@ check_request(request, expect, ignore) io.write("testing proxy with redirection: ") request = { url = "http://" .. host .. prefix, - proxyhost = proxyhost, - proxyport = proxyport + proxy = proxy } expect = { body = index,