diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-06-18 21:41:44 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-06-18 21:41:44 +0000 |
| commit | 7ed89c97f760600df238f9853ee453570935870f (patch) | |
| tree | a17573a43815071e35f85557519fefca739ef7ef | |
| parent | ac4aac0909da26befaaeb6b415f66cf35b6980e0 (diff) | |
| download | luasocket-7ed89c97f760600df238f9853ee453570935870f.tar.gz luasocket-7ed89c97f760600df238f9853ee453570935870f.tar.bz2 luasocket-7ed89c97f760600df238f9853ee453570935870f.zip | |
2.0 alpha RELEASED!
| -rw-r--r-- | NEW | 2 | ||||
| -rw-r--r-- | TODO | 157 | ||||
| -rw-r--r-- | etc/README | 20 | ||||
| -rw-r--r-- | etc/lp.lua | 402 | ||||
| -rw-r--r-- | makefile.dist | 6 | ||||
| -rw-r--r-- | samples/README | 7 | ||||
| -rw-r--r-- | src/except.c | 23 | ||||
| -rw-r--r-- | src/ftp.lua | 16 | ||||
| -rw-r--r-- | src/http.lua | 23 | ||||
| -rw-r--r-- | src/smtp.lua | 7 | ||||
| -rw-r--r-- | src/socket.lua | 2 | ||||
| -rw-r--r-- | src/tp.lua | 49 | ||||
| -rw-r--r-- | test/httptest.lua | 9 | ||||
| -rw-r--r-- | test/testsrvr.lua | 1 |
14 files changed, 480 insertions, 244 deletions
| @@ -56,7 +56,7 @@ the changes that made it into version 2.0: | |||
| 56 | LUASOCKET_DEBUG was defined, but it turns out they might be useful for | 56 | LUASOCKET_DEBUG was defined, but it turns out they might be useful for |
| 57 | applications; | 57 | applications; |
| 58 | 58 | ||
| 59 | <> 'socket.try' and 'socket.protect' provide a simple | 59 | <> 'socket.newtry' and 'socket.protect' provide a simple |
| 60 | interface to exceptions that proved very in the implementation of | 60 | interface to exceptions that proved very in the implementation of |
| 61 | high-level modules; | 61 | high-level modules; |
| 62 | 62 | ||
| @@ -1,163 +1,12 @@ | |||
| 1 | 1 | make select interrupt safe | |
| 2 | 2 | adicionar exemplos de expansão: pipe, local, named pipe | |
| 3 | ajeitar os README.* | ||
| 4 | ajeitar as referencias a RFCS e LTNS em todos os arquivos. | ||
| 5 | |||
| 6 | make sure sockets are closed when exceptions are raised | ||
| 7 | |||
| 8 | check garbage collection in test*.lua | ||
| 9 | |||
| 10 | |||
| 11 | manual | ||
| 12 | socket.newtry | ||
| 13 | *socket.skip | ||
| 14 | *send return convention changed. | ||
| 15 | * compatibility: select sets are associative | ||
| 16 | * add socket.connect and socket.bind to the manual | ||
| 17 | * add shutdown | ||
| 18 | * add gethostname | ||
| 19 | check all occurences of it's | ||
| 20 | * the need of a content-length header in the post method... | ||
| 21 | * notice the change in callback conventions | ||
| 22 | * the callback.lua module and the new mime module. | ||
| 23 | * escape and unescape in url, not in code! | ||
| 24 | * add timeout and proxy to request table | ||
| 25 | * change stay to redirect | ||
| 26 | * socket.time and socket.sleep | ||
| 27 | * - connect with timeout | ||
| 28 | local connect | ||
| 29 | * add thanks to 'carlos cassino' and 'david burgess' | ||
| 30 | * add new ip- options and reuseaddr option | ||
| 31 | * - add listen to manual | ||
| 32 | * bind method doesn't do listen anymore | ||
| 33 | * bind doesn't turn an object into a server object: listen does. | ||
| 34 | |||
| 35 | tests | ||
| 36 | checar todos os metodos | ||
| 37 | checar todas as globais | ||
| 38 | checar garbage collection | ||
| 39 | check for interrupts | ||
| 40 | |||
| 41 | wrp can't break lines in the middle of a line break. | ||
| 42 | |||
| 43 | add comments into each C module. | ||
| 44 | testar os options! | ||
| 45 | |||
| 46 | |||
| 47 | Read about | ||
| 48 | 250-ENHANCEDSTATUSCODES | ||
| 49 | 250-PIPELINING | ||
| 50 | 250-8BITMIME | ||
| 51 | 250-SIZE | ||
| 52 | 250-DSN | ||
| 53 | 250-ETRN | ||
| 54 | 250-AUTH GSSAPI | ||
| 55 | 250-DELIVERBY | ||
| 56 | 250 HELP | ||
| 57 | |||
| 58 | Change return of send and receive callbacks to allow for | ||
| 59 | new functions. "" signals end of transmission. Pass total | ||
| 60 | number of bytes in request table for HTTP. Callback has nothing | ||
| 61 | to do with it. | ||
| 62 | |||
| 63 | Make sure nobody can fuck up with the metatables... | ||
| 64 | |||
| 65 | |||
| 66 | |||
| 67 | Adjust dates in all files | ||
| 68 | |||
| 69 | Test the library on every system possible | ||
| 70 | |||
| 71 | Add service name translation. | 3 | Add service name translation. |
| 72 | Ajeitar o protocolo da luaopen_socket()... sei lá qual é. | 4 | testar os options! |
| 73 | |||
| 74 | |||
| 75 | - adicionar exemplos de expansão: pipe, local, named pipe | ||
| 76 | |||
| 77 | |||
| 78 | - Fazer compilar com g++ | 5 | - Fazer compilar com g++ |
| 79 | - Thread-safe | 6 | - Thread-safe |
| 80 | - proteger get*by*.* com um mutex GLOBAL! | 7 | - proteger get*by*.* com um mutex GLOBAL! |
| 81 | - proteger ou atomizar o conjunto (timedout, receive), (timedout, send) | 8 | - proteger ou atomizar o conjunto (timedout, receive), (timedout, send) |
| 82 | - inet_ntoa também é uma merda. | 9 | - inet_ntoa também é uma merda. |
| 83 | - SSL | 10 | - SSL |
| 84 | |||
| 85 | - unix 92 bytes maximo no endereço, incluindo o zero | 11 | - unix 92 bytes maximo no endereço, incluindo o zero |
| 86 | - unix 9216 maximo de datagram size | 12 | - unix 9216 maximo de datagram size |
| 87 | |||
| 88 | -------------- | ||
| 89 | these are done | ||
| 90 | -------------- | ||
| 91 | |||
| 92 | * tirar socket.url socket.ftp etc do manual. agora os namespaces | ||
| 93 | estao liberados. | ||
| 94 | * falar sobre o novo esquema de namespace | ||
| 95 | * ajeitar o manual sobre select, mais liberal agora | ||
| 96 | * make sure filter.chain fails gracefully. | ||
| 97 | * ajeitar select. upvalue nao tem nada a ver... | ||
| 98 | * should be interrupt-safe | ||
| 99 | * notice the change in callback conventions | ||
| 100 | * new mime module replacing old code module (faster, more functionality) | ||
| 101 | * new socket options (many) | ||
| 102 | * only allocate in case of success | ||
| 103 | * optimize for success (only call select if fails) | ||
| 104 | * add proxy support to http | ||
| 105 | * add gethostname | ||
| 106 | * local connect | ||
| 107 | * connect with timeout | ||
| 108 | * change code to mime | ||
| 109 | * change stay to redirect | ||
| 110 | * add shutdown | ||
| 111 | * change send/recv to avoid using select | ||
| 112 | * O location do "redirect" pode ser relativo ao servidor atual (não pode, | ||
| 113 | mas os servidores fazem merda...) | ||
| 114 | * Ajeitar para Lua 5.0 | ||
| 115 | * Padronizar os retornos de funccao | ||
| 116 | * Separar as classes em arquivos | ||
| 117 | * Retorno de sendto em datagram sockets pode ser refused | ||
| 118 | * select sets are now associative | ||
| 119 | * colocar pump.all, pump.step | ||
| 120 | * mudar ltn12.html e usar o exemplo source.cat que está muito melhor. | ||
| 121 | * break smtp.send into c = smtp.open, c:send() c:close() | ||
| 122 | * fazer com que a socket.source e socket.sink sejam "selectable". | ||
| 123 | * change mime.eol to output marker on detection of first candidate, instead | ||
| 124 | of on the second. that way it works in one pass for strings that end with | ||
| 125 | one candidate. | ||
| 126 | * unify backbone of smtp and ftp | ||
| 127 | * unify filter and send/receive callback. new sink/source/pump idea. | ||
| 128 | * get rid of aux_optlstring | ||
| 129 | * get rid of unpack in mime.lua | ||
| 130 | * create socket.(sink|source).simplify | ||
| 131 | * break chain into a simpler binary chain and a complex (recursive) one. | ||
| 132 | * Create a passive mode option for the FTP (good for firewall). | ||
| 133 | * Modules should return their namespace table in the end of the chunk. | ||
| 134 | * get.lua precisa de ftp.get com url e sink | ||
| 135 | * conjunto associativo | ||
| 136 | * colocar um userdata com gc metamethod pra chamar sock_close (WSAClose); | ||
| 137 | * call select before accept, not after, dumbass! | ||
| 138 | * get rid of setnonblocking/setblocking in the bind function | ||
| 139 | * close has to block... | ||
| 140 | * fmt is not a good name | ||
| 141 | * change wrap() to accept a number and default to "character" | ||
| 142 | * move gethostname to dns table | ||
| 143 | * get rid of _cb in name of functions? | ||
| 144 | * trust character constants in mime.c? yup. | ||
| 145 | * smtp.lua needs stuff filter | ||
| 146 | * new option.c module to put all options (TCP and UDP share...)? | ||
| 147 | * add _tostring methods! | ||
| 148 | * change all modules to use the new namespace scheme | ||
| 149 | * write some utilities that use the code.lua module and put them | ||
| 150 | * in etc, modify the README.etc file and makefile.dist (eol.lua is done) | ||
| 151 | * proxy no ftp? no | ||
| 152 | * ajeitar < e-mail > no smtp? no | ||
| 153 | * ajeitar referencias a LTN12 nos manuais | ||
| 154 | * RECEIVE MUDOU!!! (partial stuff) COLOCAR NO MANUAL. | ||
| 155 | * HTTP.lua mudou bastante também. | ||
| 156 | * falar sobre encodet/wrapt/decodet no manual sobre mime? no. | ||
| 157 | * pump.step usado em todo mundo que recebe source ou sink | ||
| 158 | * sources ans sinks are always simple in http and ftp and smtp | ||
| 159 | * expose encode/decode tables to provide extensibility for mime module | ||
| 160 | * use coroutines instead of fancy filters | ||
| 161 | * add socket.TIMEOUT to be default timeout? no. | ||
| 162 | * use gethostname it in SMTP | ||
| 163 | * smtp.o goes to mime.dll | ||
| @@ -1,24 +1,10 @@ | |||
| 1 | This directory contains code that is more useful than the examples. This code | 1 | This directory contains code that is more useful than the examples. This code |
| 2 | *is* supported. | 2 | *is* supported. |
| 3 | 3 | ||
| 4 | lua.lua | 4 | lua.lua -- new require and requirelib implementations |
| 5 | 5 | ||
| 6 | These are modules to suport dynamic loading of LuaSocket by the stand alone | 6 | This is to support dynamic loading of LuaSocket. Check the INSTALL |
| 7 | Lua Interpreter with the use of new "require" and "requirelib" functions. | 7 | file for more information. |
| 8 | For my Mac OS X box, for instance, I place all files in | ||
| 9 | /Users/diego/tec/luasocket and set the following environment variables: | ||
| 10 | |||
| 11 | LUA_INIT=@/Users/diego/tec/luasocket/lua.lua | ||
| 12 | LUA_PATH=/Users/diego/tec/luasocket/?.lua;?.lua | ||
| 13 | LUA_PATHLIB=/Users/diego/tec/luasocket/?.dylib;?.dylib | ||
| 14 | |||
| 15 | With that, I can run any luasocket application with the command line: | ||
| 16 | |||
| 17 | lua <script> | ||
| 18 | |||
| 19 | as long as the script uses "require" to load the needed namespaces. | ||
| 20 | Much nicer than having to build a new executable just to initialize | ||
| 21 | LuaSocket! | ||
| 22 | 8 | ||
| 23 | tftp.lua -- Trivial FTP client | 9 | tftp.lua -- Trivial FTP client |
| 24 | 10 | ||
diff --git a/etc/lp.lua b/etc/lp.lua new file mode 100644 index 0000000..80acf86 --- /dev/null +++ b/etc/lp.lua | |||
| @@ -0,0 +1,402 @@ | |||
| 1 | -- make sure LuaSocket is loaded | ||
| 2 | local socket = require("socket") | ||
| 3 | local ltn12 = require("ltn12") | ||
| 4 | local lp = {} | ||
| 5 | --socket.lp = lp | ||
| 6 | -- make all module globals fall into lp namespace | ||
| 7 | setmetatable(lp, { __index = _G }) | ||
| 8 | setfenv(1, lp) | ||
| 9 | |||
| 10 | -- default port | ||
| 11 | PORT = 515 | ||
| 12 | SERVER = os.getenv("SERVER_NAME") or os.getenv("COMPUTERNAME") or "localhost" | ||
| 13 | PRINTER = os.getenv("PRINTER") or "printer" | ||
| 14 | |||
| 15 | |||
| 16 | --[[ | ||
| 17 | RFC 1179 | ||
| 18 | 5.3 03 - Send queue state (short) | ||
| 19 | |||
| 20 | +----+-------+----+------+----+ | ||
| 21 | | 03 | Queue | SP | List | LF | | ||
| 22 | +----+-------+----+------+----+ | ||
| 23 | Command code - 3 | ||
| 24 | Operand 1 - Printer queue name | ||
| 25 | Other operands - User names or job numbers | ||
| 26 | |||
| 27 | If the user names or job numbers or both are supplied then only those | ||
| 28 | jobs for those users or with those numbers will be sent. | ||
| 29 | |||
| 30 | The response is an ASCII stream which describes the printer queue. | ||
| 31 | The stream continues until the connection closes. Ends of lines are | ||
| 32 | indicated with ASCII LF control characters. The lines may also | ||
| 33 | contain ASCII HT control characters. | ||
| 34 | |||
| 35 | 5.4 04 - Send queue state (long) | ||
| 36 | |||
| 37 | +----+-------+----+------+----+ | ||
| 38 | | 04 | Queue | SP | List | LF | | ||
| 39 | +----+-------+----+------+----+ | ||
| 40 | Command code - 4 | ||
| 41 | Operand 1 - Printer queue name | ||
| 42 | Other operands - User names or job numbers | ||
| 43 | |||
| 44 | If the user names or job numbers or both are supplied then only those | ||
| 45 | jobs for those users or with those numbers will be sent. | ||
| 46 | |||
| 47 | The response is an ASCII stream which describes the printer queue. | ||
| 48 | The stream continues until the connection closes. Ends of lines are | ||
| 49 | indicated with ASCII LF control characters. The lines may also | ||
| 50 | contain ASCII HT control characters. | ||
| 51 | ]] | ||
| 52 | |||
| 53 | |||
| 54 | -- gets server acknowledement | ||
| 55 | local function recv_ack(connection) | ||
| 56 | local code, current, separator, _ | ||
| 57 | local ack = socket.try(connection:receive(1)) | ||
| 58 | if string.char(0) ~= ack then | ||
| 59 | connection:close(); error"failed to receive server acknowledement" | ||
| 60 | end | ||
| 61 | end | ||
| 62 | |||
| 63 | -- sends client acknowledement | ||
| 64 | local function send_ack(connection) | ||
| 65 | local sent = socket.try(connection:send(string.char(0))) | ||
| 66 | if not sent or sent ~= 1 then | ||
| 67 | connection:close(); | ||
| 68 | error"failed to send acknowledgement" | ||
| 69 | end | ||
| 70 | end | ||
| 71 | |||
| 72 | -- sends queue request | ||
| 73 | -- 5.2 02 - Receive a printer job | ||
| 74 | -- | ||
| 75 | -- +----+-------+----+ | ||
| 76 | -- | 02 | Queue | LF | | ||
| 77 | -- +----+-------+----+ | ||
| 78 | -- Command code - 2 | ||
| 79 | -- Operand - Printer queue name | ||
| 80 | -- | ||
| 81 | -- Receiving a job is controlled by a second level of commands. The | ||
| 82 | -- daemon is given commands by sending them over the same connection. | ||
| 83 | -- The commands are described in the next section (6). | ||
| 84 | -- | ||
| 85 | -- After this command is sent, the client must read an acknowledgement | ||
| 86 | -- octet from the daemon. A positive acknowledgement is an octet of | ||
| 87 | -- zero bits. A negative acknowledgement is an octet of any other | ||
| 88 | -- pattern. | ||
| 89 | local function send_queue(connection,queue) | ||
| 90 | if not queue then queue=PRINTER end | ||
| 91 | local str = string.format("\2%s\10",queue) | ||
| 92 | local sent = socket.try(connection:send(str)) | ||
| 93 | if not sent or sent ~= string.len(str) then | ||
| 94 | error "failed to send print request" | ||
| 95 | end | ||
| 96 | recv_ack(connection) | ||
| 97 | end | ||
| 98 | |||
| 99 | -- sends control file | ||
| 100 | -- 6.2 02 - Receive control file | ||
| 101 | -- | ||
| 102 | -- +----+-------+----+------+----+ | ||
| 103 | -- | 02 | Count | SP | Name | LF | | ||
| 104 | -- +----+-------+----+------+----+ | ||
| 105 | -- Command code - 2 | ||
| 106 | -- Operand 1 - Number of bytes in control file | ||
| 107 | -- Operand 2 - Name of control file | ||
| 108 | -- | ||
| 109 | -- The control file must be an ASCII stream with the ends of lines | ||
| 110 | -- indicated by ASCII LF. The total number of bytes in the stream is | ||
| 111 | -- sent as the first operand. The name of the control file is sent as | ||
| 112 | -- the second. It should start with ASCII "cfA", followed by a three | ||
| 113 | -- digit job number, followed by the host name which has constructed the | ||
| 114 | -- control file. Acknowledgement processing must occur as usual after | ||
| 115 | -- the command is sent. | ||
| 116 | -- | ||
| 117 | -- The next "Operand 1" octets over the same TCP connection are the | ||
| 118 | -- intended contents of the control file. Once all of the contents have | ||
| 119 | -- been delivered, an octet of zero bits is sent as an indication that | ||
| 120 | -- the file being sent is complete. A second level of acknowledgement | ||
| 121 | -- processing must occur at this point. | ||
| 122 | |||
| 123 | -- sends data file | ||
| 124 | -- 6.3 03 - Receive data file | ||
| 125 | -- | ||
| 126 | -- +----+-------+----+------+----+ | ||
| 127 | -- | 03 | Count | SP | Name | LF | | ||
| 128 | -- +----+-------+----+------+----+ | ||
| 129 | -- Command code - 3 | ||
| 130 | -- Operand 1 - Number of bytes in data file | ||
| 131 | -- Operand 2 - Name of data file | ||
| 132 | -- | ||
| 133 | -- The data file may contain any 8 bit values at all. The total number | ||
| 134 | -- of bytes in the stream may be sent as the first operand, otherwise | ||
| 135 | -- the field should be cleared to 0. The name of the data file should | ||
| 136 | -- start with ASCII "dfA". This should be followed by a three digit job | ||
| 137 | -- number. The job number should be followed by the host name which has | ||
| 138 | -- constructed the data file. Interpretation of the contents of the | ||
| 139 | -- data file is determined by the contents of the corresponding control | ||
| 140 | -- file. If a data file length has been specified, the next "Operand 1" | ||
| 141 | -- octets over the same TCP connection are the intended contents of the | ||
| 142 | -- data file. In this case, once all of the contents have been | ||
| 143 | -- delivered, an octet of zero bits is sent as an indication that the | ||
| 144 | -- file being sent is complete. A second level of acknowledgement | ||
| 145 | -- processing must occur at this point. | ||
| 146 | |||
| 147 | |||
| 148 | local function send_hdr(connection,control) | ||
| 149 | local sent = socket.try(connection:send(control)) | ||
| 150 | if not sent or sent < 1 then | ||
| 151 | error "failed to send file" | ||
| 152 | end | ||
| 153 | recv_ack(connection) | ||
| 154 | end | ||
| 155 | |||
| 156 | |||
| 157 | local function send_control(connection,control) | ||
| 158 | local sent = socket.try(connection:send(control)) | ||
| 159 | if not sent or sent < 1 then | ||
| 160 | error "failed to send file" | ||
| 161 | end | ||
| 162 | send_ack(connection) | ||
| 163 | end | ||
| 164 | |||
| 165 | local function send_data(connection,fh,size) | ||
| 166 | -- local sink = socket.sink("keep-open", connection) | ||
| 167 | -- ltn12.pump.all(source, sink) | ||
| 168 | local buf, st, message | ||
| 169 | st = true | ||
| 170 | while size > 0 do | ||
| 171 | buf,message = fh:read(8192) | ||
| 172 | if buf then | ||
| 173 | st = socket.try(connection:send(buf)) | ||
| 174 | size = size - st | ||
| 175 | else | ||
| 176 | if size ~= 0 then | ||
| 177 | connection:close() | ||
| 178 | return nil, "file size mismatch" | ||
| 179 | end | ||
| 180 | end | ||
| 181 | end | ||
| 182 | send_ack(connection) | ||
| 183 | recv_ack(connection) | ||
| 184 | return size,nil | ||
| 185 | end | ||
| 186 | |||
| 187 | |||
| 188 | --[[ | ||
| 189 | |||
| 190 | local control_dflt = { | ||
| 191 | "H"..string.sub(socket.hostname,1,31).."\10", -- host | ||
| 192 | "C"..string.sub(socket.hostname,1,31).."\10", -- class | ||
| 193 | "J"..string.sub(filename,1,99).."\10", -- jobname | ||
| 194 | "L"..string.sub(user,1,31).."\10", -- print banner page | ||
| 195 | "I"..tonumber(indent).."\10", -- indent column count ('f' only) | ||
| 196 | "M"..string.sub(mail,1,128).."\10", -- mail when printed user@host | ||
| 197 | "N"..string.sub(filename,1,131).."\10", -- name of source file | ||
| 198 | "P"..string.sub(user,1,31).."\10", -- user name | ||
| 199 | "T"..string.sub(title,1,79).."\10", -- title for banner ('p' only) | ||
| 200 | "W"..tonumber(width or 132).."\10", -- width of print f,l,p only | ||
| 201 | |||
| 202 | "f"..file.."\10", -- formatted print (remove control chars) | ||
| 203 | "l"..file.."\10", -- print | ||
| 204 | "o"..file.."\10", -- postscript | ||
| 205 | "p"..file.."\10", -- pr format - requires T, L | ||
| 206 | "r"..file.."\10", -- fortran format | ||
| 207 | "U"..file.."\10", -- Unlink (data file only) | ||
| 208 | } | ||
| 209 | |||
| 210 | ]] | ||
| 211 | |||
| 212 | -- generate a varying job number | ||
| 213 | local function getjobno(connection) | ||
| 214 | -- print(math.mod(socket.time() * 1000, port)) -- ok for windows | ||
| 215 | -- print(os.time() / port,math.random(0,999)) | ||
| 216 | return math.random(0,999) | ||
| 217 | end | ||
| 218 | |||
| 219 | local function getcon(localhost,option) | ||
| 220 | local skt, st, message | ||
| 221 | local localport = 721 | ||
| 222 | if not option then | ||
| 223 | error('no options',0) | ||
| 224 | end | ||
| 225 | if option.localbind then | ||
| 226 | repeat | ||
| 227 | -- bind to a local port (if we can) | ||
| 228 | skt = socket.try(socket.tcp()) | ||
| 229 | skt:settimeout(30) | ||
| 230 | |||
| 231 | st, message = skt:bind(localhost,localport,-1); | ||
| 232 | -- print("bind",st,message) | ||
| 233 | if st then | ||
| 234 | st,message = skt:connect(option.host or SERVER, option.port or PORT) | ||
| 235 | -- print("connect",st,message) | ||
| 236 | end | ||
| 237 | -- print(st,localport,message) | ||
| 238 | if not st then | ||
| 239 | localport = localport + 1 | ||
| 240 | skt:close() | ||
| 241 | end | ||
| 242 | until st or localport > 731 or (not st and message ~= "local address already in use") | ||
| 243 | if st then return skt end | ||
| 244 | end | ||
| 245 | return socket.try(socket.connect(option.host or SERVER, option.port or PORT)) | ||
| 246 | end | ||
| 247 | |||
| 248 | local format_codes = { | ||
| 249 | binary = 'l', | ||
| 250 | text = 'f', | ||
| 251 | ps = 'o', | ||
| 252 | pr = 'p', | ||
| 253 | fortran = 'r', | ||
| 254 | l = 'l', | ||
| 255 | r = 'r', | ||
| 256 | o = 'o', | ||
| 257 | p = 'p', | ||
| 258 | f = 'f' | ||
| 259 | } | ||
| 260 | |||
| 261 | lp.send = socket.protect(function(file, option) | ||
| 262 | if not file then error "invalid file name" end | ||
| 263 | if not option or type(option) ~= "table" then error "invalid options" end | ||
| 264 | local fh = socket.try(io.open(file,"rb")) | ||
| 265 | -- get total size | ||
| 266 | local datafile_size = fh:seek("end") | ||
| 267 | -- go back to start of file | ||
| 268 | fh:seek("set") | ||
| 269 | math.randomseed(socket.time() * 1000) | ||
| 270 | local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME") or "localhost" | ||
| 271 | |||
| 272 | -- local connection, message = skt:connect(option.host or SERVER, option.port or PORT) | ||
| 273 | |||
| 274 | local connection = getcon(localhost,option) | ||
| 275 | |||
| 276 | -- format the control file | ||
| 277 | local jobno = getjobno(connection) | ||
| 278 | local localip = socket.dns.toip(localhost) | ||
| 279 | localhost = string.sub(localhost,1,31) | ||
| 280 | |||
| 281 | local user = string.sub(option.user or os.getenv("LPRUSER") or os.getenv("USERNAME") | ||
| 282 | or os.getenv("USER") or "anonymous",1,31) | ||
| 283 | |||
| 284 | local lpfile = string.format("dfA%3.3d%-s", jobno, localhost); | ||
| 285 | |||
| 286 | local fmt = format_codes[option.format] or 'l' | ||
| 287 | |||
| 288 | local class = string.sub(option.class or localip or localhost,1,31) | ||
| 289 | |||
| 290 | local _,_,ctlfn = string.find(file,".*[%/%\\](.*)") | ||
| 291 | ctlfn = string.sub(ctlfn or file,1,131) | ||
| 292 | |||
| 293 | local cfile = | ||
| 294 | string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n", | ||
| 295 | localhost, | ||
| 296 | class, | ||
| 297 | option.job or ctlfn, | ||
| 298 | user, | ||
| 299 | fmt, lpfile, | ||
| 300 | lpfile, | ||
| 301 | ctlfn); -- mandatory part of ctl file | ||
| 302 | if (option.banner) then cfile = cfile .. 'L'..user..'\10' end | ||
| 303 | if (option.indent) then cfile = cfile .. 'I'..tonumber(option.indent)..'\10' end | ||
| 304 | if (option.mail) then cfile = cfile .. 'M'..string.sub((option.mail),1,128)..'\10' end | ||
| 305 | if (fmt == 'p' and option.title) then cfile = cfile .. 'T'..string.sub((option.title),1,79)..'\10' end | ||
| 306 | if ((fmt == 'p' or fmt == 'l' or fmt == 'f') and option.width) then | ||
| 307 | cfile = cfile .. 'W'..tonumber(option,width)..'\10' | ||
| 308 | end | ||
| 309 | |||
| 310 | connection:settimeout(option.timeout or 65) | ||
| 311 | |||
| 312 | -- send the queue header | ||
| 313 | send_queue(connection,option.queue) | ||
| 314 | |||
| 315 | -- send the control file header | ||
| 316 | local cfilecmd = string.format("\2%d cfA%3.3d%-s\n",string.len(cfile), jobno, localhost); | ||
| 317 | send_hdr(connection,cfilecmd) | ||
| 318 | |||
| 319 | -- send the control file | ||
| 320 | send_control(connection,cfile) | ||
| 321 | |||
| 322 | -- send the data file header | ||
| 323 | local dfilecmd = string.format("\3%d dfA%3.3d%-s\n",datafile_size, jobno, localhost); | ||
| 324 | send_hdr(connection,dfilecmd) | ||
| 325 | |||
| 326 | -- send the data file | ||
| 327 | send_data(connection,fh,datafile_size) | ||
| 328 | fh:close() | ||
| 329 | connection:close(); | ||
| 330 | return datafile_size | ||
| 331 | end) | ||
| 332 | |||
| 333 | |||
| 334 | --socket.lpq({host=,queue=printer|'*', format='l'|'s', list=}) | ||
| 335 | lp.query = socket.protect(function(p) | ||
| 336 | if not p then p={} end | ||
| 337 | local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME") or "localhost" | ||
| 338 | local connection = getcon(localhost,p) | ||
| 339 | local fmt,data | ||
| 340 | if string.sub(p.format or 's',1,1) == 's' then fmt = 3 else fmt = 4 end | ||
| 341 | local sent = socket.try(connection:send(string.format("%c%s %s\n", fmt, p.queue or "*", p.list or ""))) | ||
| 342 | local data = socket.try(connection:receive("*a")) | ||
| 343 | io.write(data) | ||
| 344 | connection:close() | ||
| 345 | return tostring(string.len(data)) | ||
| 346 | end) | ||
| 347 | |||
| 348 | --for k,v in arg do print(k,v) end | ||
| 349 | local function usage() | ||
| 350 | print('\nUsage: lp filename [keyword=val...]\n') | ||
| 351 | print('Valid keywords are :') | ||
| 352 | print( | ||
| 353 | ' host=remote host or IP address (default "localhost")\n' .. | ||
| 354 | ' queue=remote queue or printer name (default "printer")\n' .. | ||
| 355 | ' port=remote port number (default 515)\n' .. | ||
| 356 | ' user=sending user name\n' .. | ||
| 357 | ' format=["binary" | "text" | "ps" | "pr" | "fortran"] (default "binary")\n' .. | ||
| 358 | ' banner=true|false\n' .. | ||
| 359 | ' indent=number of columns to indent\n' .. | ||
| 360 | ' mail=email of address to notify when print is complete\n' .. | ||
| 361 | ' title=title to use for "pr" format\n' .. | ||
| 362 | ' width=width for "text" or "pr" formats\n' .. | ||
| 363 | ' class=\n' .. | ||
| 364 | ' job=\n' .. | ||
| 365 | ' name=\n' .. | ||
| 366 | ' localbind=true|false\n' | ||
| 367 | ) | ||
| 368 | return nil | ||
| 369 | end | ||
| 370 | |||
| 371 | if not arg or not arg[1] then | ||
| 372 | return usage() | ||
| 373 | end | ||
| 374 | |||
| 375 | do | ||
| 376 | local s="opt = {" | ||
| 377 | for i = 2 , table.getn(arg), 1 do | ||
| 378 | s = s .. string.gsub(arg[i],"[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)","%1%=\"%2\",\n") | ||
| 379 | end | ||
| 380 | s = s .. "};\n" | ||
| 381 | assert(loadstring(s))(); | ||
| 382 | if not arg[2] then | ||
| 383 | return usage() | ||
| 384 | end | ||
| 385 | if arg[1] ~= "query" then | ||
| 386 | r,e=lp.send(arg[1],opt) | ||
| 387 | io.stderr:write(tostring(r or e),'\n') | ||
| 388 | else | ||
| 389 | r,e=lp.query(opt) | ||
| 390 | io.stderr:write(tostring(r or e),'\n') | ||
| 391 | end | ||
| 392 | end | ||
| 393 | |||
| 394 | -- trivial tests | ||
| 395 | --lua lp.lua lp.lua queue=default host=localhost | ||
| 396 | --lua lp.lua lp.lua queue=default host=localhost format=binary localbind=1 | ||
| 397 | --lua lp.lua query queue=default host=localhost | ||
| 398 | collectgarbage() | ||
| 399 | collectgarbage() | ||
| 400 | --print(socket.lp.query{host='localhost', queue="default"}) | ||
| 401 | |||
| 402 | return nil | ||
diff --git a/makefile.dist b/makefile.dist index 19c85b5..fec6579 100644 --- a/makefile.dist +++ b/makefile.dist | |||
| @@ -29,6 +29,7 @@ EXAMPLES = \ | |||
| 29 | eol.lua \ | 29 | eol.lua \ |
| 30 | listener.lua \ | 30 | listener.lua \ |
| 31 | qp.lua \ | 31 | qp.lua \ |
| 32 | lp.lua \ | ||
| 32 | talker.lua \ | 33 | talker.lua \ |
| 33 | tinyirc.lua | 34 | tinyirc.lua |
| 34 | 35 | ||
| @@ -101,14 +102,13 @@ dist: | |||
| 101 | mkdir -p $(DIST)/tests | 102 | mkdir -p $(DIST)/tests |
| 102 | mkdir -p $(DIST)/etc | 103 | mkdir -p $(DIST)/etc |
| 103 | mkdir -p $(DIST)/lua | 104 | mkdir -p $(DIST)/lua |
| 104 | mkdir -p $(DIST)/make | ||
| 105 | mkdir -p $(DIST)/manual | 105 | mkdir -p $(DIST)/manual |
| 106 | cp -vf $(CORE) $(DIST) | 106 | cp -vf $(CORE) $(DIST) |
| 107 | cp -vf README $(DIST) | 107 | cp -vf README $(DIST) |
| 108 | cp -vf NEW $(DIST) | 108 | cp -vf NEW $(DIST) |
| 109 | cp -vf LICENSE $(DIST) | 109 | cp -vf LICENSE $(DIST) |
| 110 | cp -vf $(MAKE) $(DIST)/make | 110 | cp -vf $(MAKE) $(DIST) |
| 111 | cp -vf make.README $(DIST)/make/README | 111 | cp -vf make.README $(DIST)/INSTALL |
| 112 | cp -vf $(LUA) $(DIST)/lua | 112 | cp -vf $(LUA) $(DIST)/lua |
| 113 | cp -vf lua.README $(DIST)/lua/README | 113 | cp -vf lua.README $(DIST)/lua/README |
| 114 | cp -vf $(EXAMPLES) $(DIST)/examples | 114 | cp -vf $(EXAMPLES) $(DIST)/examples |
diff --git a/samples/README b/samples/README index b5802e5..6e7ee77 100644 --- a/samples/README +++ b/samples/README | |||
| @@ -19,6 +19,12 @@ printed by listen.lua. | |||
| 19 | These are tiny programs that perform Base64, Quoted-Printable and | 19 | These are tiny programs that perform Base64, Quoted-Printable and |
| 20 | end-of-line marker conversions. | 20 | end-of-line marker conversions. |
| 21 | 21 | ||
| 22 | lp.lua -- lp client | ||
| 23 | |||
| 24 | This is a cool program written by David Burgess to print files using the | ||
| 25 | Line Printer Daemon protocol, widely used in Unix machines. | ||
| 26 | Just run 'lua lp.lua <filename> queue=<printername>' and the file will print! | ||
| 27 | |||
| 22 | cddb.lua -- CDDB client | 28 | cddb.lua -- CDDB client |
| 23 | 29 | ||
| 24 | This is the first try on a simple CDDB client. Not really useful, but one | 30 | This is the first try on a simple CDDB client. Not really useful, but one |
| @@ -26,7 +32,6 @@ day it might become a module. | |||
| 26 | 32 | ||
| 27 | daytimeclnt.lua -- day time client | 33 | daytimeclnt.lua -- day time client |
| 28 | 34 | ||
| 29 | |||
| 30 | Just run the program to retrieve the hour and date in readable form from | 35 | Just run the program to retrieve the hour and date in readable form from |
| 31 | any server running an UDP daytime daemon. | 36 | any server running an UDP daytime daemon. |
| 32 | 37 | ||
diff --git a/src/except.c b/src/except.c index 53a65ac..68abf70 100644 --- a/src/except.c +++ b/src/except.c | |||
| @@ -12,33 +12,21 @@ | |||
| 12 | /*=========================================================================*\ | 12 | /*=========================================================================*\ |
| 13 | * Internal function prototypes. | 13 | * Internal function prototypes. |
| 14 | \*=========================================================================*/ | 14 | \*=========================================================================*/ |
| 15 | static int global_try(lua_State *L); | ||
| 16 | static int global_protect(lua_State *L); | 15 | static int global_protect(lua_State *L); |
| 17 | static int global_newtry(lua_State *L); | 16 | static int global_newtry(lua_State *L); |
| 18 | static int protected(lua_State *L); | 17 | static int protected(lua_State *L); |
| 19 | static int finalize(lua_State *L); | 18 | static int finalize(lua_State *L); |
| 19 | static int do_nothing(lua_State *L); | ||
| 20 | 20 | ||
| 21 | /* except functions */ | 21 | /* except functions */ |
| 22 | static luaL_reg func[] = { | 22 | static luaL_reg func[] = { |
| 23 | {"try", global_try}, | ||
| 24 | {"newtry", global_newtry}, | 23 | {"newtry", global_newtry}, |
| 25 | {"protect", global_protect}, | 24 | {"protect", global_protect}, |
| 26 | {NULL, NULL} | 25 | {NULL, NULL} |
| 27 | }; | 26 | }; |
| 28 | 27 | ||
| 29 | /*-------------------------------------------------------------------------*\ | 28 | /*-------------------------------------------------------------------------*\ |
| 30 | * Try method | 29 | * Try factory |
| 31 | \*-------------------------------------------------------------------------*/ | ||
| 32 | static int global_try(lua_State *L) { | ||
| 33 | if (lua_isnil(L, 1) || (lua_isboolean(L, 1) && !lua_toboolean(L, 1))) { | ||
| 34 | lua_settop(L, 2); | ||
| 35 | lua_error(L); | ||
| 36 | return 0; | ||
| 37 | } else return lua_gettop(L); | ||
| 38 | } | ||
| 39 | |||
| 40 | /*-------------------------------------------------------------------------*\ | ||
| 41 | * Finalizer factory | ||
| 42 | \*-------------------------------------------------------------------------*/ | 30 | \*-------------------------------------------------------------------------*/ |
| 43 | static int finalize(lua_State *L) { | 31 | static int finalize(lua_State *L) { |
| 44 | if (lua_isnil(L, 1) || (lua_isboolean(L, 1) && !lua_toboolean(L, 1))) { | 32 | if (lua_isnil(L, 1) || (lua_isboolean(L, 1) && !lua_toboolean(L, 1))) { |
| @@ -50,7 +38,14 @@ static int finalize(lua_State *L) { | |||
| 50 | } else return lua_gettop(L); | 38 | } else return lua_gettop(L); |
| 51 | } | 39 | } |
| 52 | 40 | ||
| 41 | static int do_nothing(lua_State *L) { | ||
| 42 | (void) L; | ||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 53 | static int global_newtry(lua_State *L) { | 46 | static int global_newtry(lua_State *L) { |
| 47 | lua_settop(L, 1); | ||
| 48 | if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); | ||
| 54 | lua_pushcclosure(L, finalize, 1); | 49 | lua_pushcclosure(L, finalize, 1); |
| 55 | return 1; | 50 | return 1; |
| 56 | } | 51 | } |
diff --git a/src/ftp.lua b/src/ftp.lua index ad02c72..1c7ea71 100644 --- a/src/ftp.lua +++ b/src/ftp.lua | |||
| @@ -32,14 +32,10 @@ local metat = { __index = {} } | |||
| 32 | 32 | ||
| 33 | function open(server, port) | 33 | function open(server, port) |
| 34 | local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT)) | 34 | local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT)) |
| 35 | local f = { tp = tp } | 35 | local f = setmetat({ tp = tp }, metat) |
| 36 | -- make sure everything gets closed in an exception | 36 | -- make sure everything gets closed in an exception |
| 37 | f.try = socket.newtry(function() | 37 | f.try = socket.newtry(function() f:close() end) |
| 38 | tp:close() | 38 | return f |
| 39 | if f.data then f.data:close() end | ||
| 40 | if f.server then f.server:close() end | ||
| 41 | end) | ||
| 42 | return setmetatable(f, metat) | ||
| 43 | end | 39 | end |
| 44 | 40 | ||
| 45 | function metat.__index:portconnect() | 41 | function metat.__index:portconnect() |
| @@ -173,13 +169,9 @@ function metat.__index:quit() | |||
| 173 | end | 169 | end |
| 174 | 170 | ||
| 175 | function metat.__index:close() | 171 | function metat.__index:close() |
| 176 | self.tp:close() | ||
| 177 | if self.data then self.data:close() end | 172 | if self.data then self.data:close() end |
| 178 | if self.server then self.server:close() end | 173 | if self.server then self.server:close() end |
| 179 | self.tp = nil | 174 | return self.tp:close() |
| 180 | self.data = nil | ||
| 181 | self.server = nil | ||
| 182 | return 1 | ||
| 183 | end | 175 | end |
| 184 | 176 | ||
| 185 | ----------------------------------------------------------------------------- | 177 | ----------------------------------------------------------------------------- |
diff --git a/src/http.lua b/src/http.lua index d8889e1..9c568bc 100644 --- a/src/http.lua +++ b/src/http.lua | |||
| @@ -32,11 +32,12 @@ local metat = { __index = {} } | |||
| 32 | 32 | ||
| 33 | function open(host, port) | 33 | function open(host, port) |
| 34 | local c = socket.try(socket.tcp()) | 34 | local c = socket.try(socket.tcp()) |
| 35 | local h = setmetatable({ c = c }, metat) | ||
| 35 | -- make sure the connection gets closed on exception | 36 | -- make sure the connection gets closed on exception |
| 36 | local try = socket.newtry(function() c:close() end) | 37 | h.try = socket.newtry(function() h:close() end) |
| 37 | try(c:settimeout(TIMEOUT)) | 38 | h.try(c:settimeout(TIMEOUT)) |
| 38 | try(c:connect(host, port or PORT)) | 39 | h.try(c:connect(host, port or PORT)) |
| 39 | return setmetatable({ c = c, try = try }, metat) | 40 | return h |
| 40 | end | 41 | end |
| 41 | 42 | ||
| 42 | function metat.__index:sendrequestline(method, uri) | 43 | function metat.__index:sendrequestline(method, uri) |
| @@ -57,9 +58,8 @@ function metat.__index:sendbody(headers, source, step) | |||
| 57 | source = source or ltn12.source.empty() | 58 | source = source or ltn12.source.empty() |
| 58 | step = step or ltn12.pump.step | 59 | step = step or ltn12.pump.step |
| 59 | -- if we don't know the size in advance, send chunked and hope for the best | 60 | -- if we don't know the size in advance, send chunked and hope for the best |
| 60 | local mode | 61 | local mode = "http-chunked" |
| 61 | if headers["content-length"] then mode = "keep-open" | 62 | if headers["content-length"] then mode = "keep-open" end |
| 62 | else mode = "http-chunked" end | ||
| 63 | return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) | 63 | return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) |
| 64 | end | 64 | end |
| 65 | 65 | ||
| @@ -99,10 +99,9 @@ function metat.__index:receivebody(headers, sink, step) | |||
| 99 | step = step or ltn12.pump.step | 99 | step = step or ltn12.pump.step |
| 100 | local length = tonumber(headers["content-length"]) | 100 | local length = tonumber(headers["content-length"]) |
| 101 | local TE = headers["transfer-encoding"] | 101 | local TE = headers["transfer-encoding"] |
| 102 | local mode | 102 | local mode = "default" -- connection close |
| 103 | if TE and TE ~= "identity" then mode = "http-chunked" | 103 | if TE and TE ~= "identity" then mode = "http-chunked" |
| 104 | elseif tonumber(headers["content-length"]) then mode = "by-length" | 104 | elseif tonumber(headers["content-length"]) then mode = "by-length" end |
| 105 | else mode = "default" end | ||
| 106 | return self.try(ltn12.pump.all(socket.source(mode, self.c, length), | 105 | return self.try(ltn12.pump.all(socket.source(mode, self.c, length), |
| 107 | sink, step)) | 106 | sink, step)) |
| 108 | end | 107 | end |
| @@ -191,9 +190,9 @@ function tauthorize(reqt) | |||
| 191 | end | 190 | end |
| 192 | 191 | ||
| 193 | function tredirect(reqt, headers) | 192 | function tredirect(reqt, headers) |
| 194 | -- the RFC says the redirect URL has to be absolute, but some | ||
| 195 | -- servers do not respect that | ||
| 196 | return trequest { | 193 | return trequest { |
| 194 | -- the RFC says the redirect URL has to be absolute, but some | ||
| 195 | -- servers do not respect that | ||
| 197 | url = url.absolute(reqt, headers["location"]), | 196 | url = url.absolute(reqt, headers["location"]), |
| 198 | source = reqt.source, | 197 | source = reqt.source, |
| 199 | sink = reqt.sink, | 198 | sink = reqt.sink, |
diff --git a/src/smtp.lua b/src/smtp.lua index d6357d2..70b511c 100644 --- a/src/smtp.lua +++ b/src/smtp.lua | |||
| @@ -60,7 +60,7 @@ function metat.__index:quit() | |||
| 60 | end | 60 | end |
| 61 | 61 | ||
| 62 | function metat.__index:close() | 62 | function metat.__index:close() |
| 63 | return self.try(self.tp:close()) | 63 | return self.tp:close() |
| 64 | end | 64 | end |
| 65 | 65 | ||
| 66 | function metat.__index:login(user, password) | 66 | function metat.__index:login(user, password) |
| @@ -104,9 +104,10 @@ end | |||
| 104 | 104 | ||
| 105 | function open(server, port) | 105 | function open(server, port) |
| 106 | local tp = socket.try(tp.connect(server or SERVER, port or PORT, TIMEOUT)) | 106 | local tp = socket.try(tp.connect(server or SERVER, port or PORT, TIMEOUT)) |
| 107 | local s = setmetatable({tp = tp}, metat) | ||
| 107 | -- make sure tp is closed if we get an exception | 108 | -- make sure tp is closed if we get an exception |
| 108 | local try = socket.newtry(function() tp:close() end) | 109 | local try = socket.newtry(function() s:close() end) |
| 109 | return setmetatable({ tp = tp, try = try}, metat) | 110 | return s |
| 110 | end | 111 | end |
| 111 | 112 | ||
| 112 | --------------------------------------------------------------------------- | 113 | --------------------------------------------------------------------------- |
diff --git a/src/socket.lua b/src/socket.lua index 0a681bf..4d64651 100644 --- a/src/socket.lua +++ b/src/socket.lua | |||
| @@ -37,6 +37,8 @@ function socket.bind(host, port, backlog) | |||
| 37 | return sock | 37 | return sock |
| 38 | end | 38 | end |
| 39 | 39 | ||
| 40 | socket.try = socket.newtry() | ||
| 41 | |||
| 40 | function socket.choose(table) | 42 | function socket.choose(table) |
| 41 | return function(name, opt1, opt2) | 43 | return function(name, opt1, opt2) |
| 42 | if type(name) ~= "string" then | 44 | if type(name) ~= "string" then |
| @@ -20,16 +20,16 @@ TIMEOUT = 60 | |||
| 20 | -- Implementation | 20 | -- Implementation |
| 21 | ----------------------------------------------------------------------------- | 21 | ----------------------------------------------------------------------------- |
| 22 | -- gets server reply (works for SMTP and FTP) | 22 | -- gets server reply (works for SMTP and FTP) |
| 23 | local function get_reply(control) | 23 | local function get_reply(c) |
| 24 | local code, current, sep | 24 | local code, current, sep |
| 25 | local line, err = control:receive() | 25 | local line, err = c:receive() |
| 26 | local reply = line | 26 | local reply = line |
| 27 | if err then return nil, err end | 27 | if err then return nil, err end |
| 28 | code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) | 28 | code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) |
| 29 | if not code then return nil, "invalid server reply" end | 29 | if not code then return nil, "invalid server reply" end |
| 30 | if sep == "-" then -- reply is multiline | 30 | if sep == "-" then -- reply is multiline |
| 31 | repeat | 31 | repeat |
| 32 | line, err = control:receive() | 32 | line, err = c:receive() |
| 33 | if err then return nil, err end | 33 | if err then return nil, err end |
| 34 | current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) | 34 | current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) |
| 35 | reply = reply .. "\n" .. line | 35 | reply = reply .. "\n" .. line |
| @@ -43,7 +43,7 @@ end | |||
| 43 | local metat = { __index = {} } | 43 | local metat = { __index = {} } |
| 44 | 44 | ||
| 45 | function metat.__index:check(ok) | 45 | function metat.__index:check(ok) |
| 46 | local code, reply = get_reply(self.control) | 46 | local code, reply = get_reply(self.c) |
| 47 | if not code then return nil, reply end | 47 | if not code then return nil, reply end |
| 48 | if type(ok) ~= "function" then | 48 | if type(ok) ~= "function" then |
| 49 | if type(ok) == "table" then | 49 | if type(ok) == "table" then |
| @@ -59,50 +59,55 @@ function metat.__index:check(ok) | |||
| 59 | end | 59 | end |
| 60 | 60 | ||
| 61 | function metat.__index:command(cmd, arg) | 61 | function metat.__index:command(cmd, arg) |
| 62 | if arg then return self.control:send(cmd .. " " .. arg.. "\r\n") | 62 | if arg then return self.c:send(cmd .. " " .. arg.. "\r\n") |
| 63 | else return self.control:send(cmd .. "\r\n") end | 63 | else return self.c:send(cmd .. "\r\n") end |
| 64 | end | 64 | end |
| 65 | 65 | ||
| 66 | function metat.__index:sink(snk, pat) | 66 | function metat.__index:sink(snk, pat) |
| 67 | local chunk, err = control:receive(pat) | 67 | local chunk, err = c:receive(pat) |
| 68 | return snk(chunk, err) | 68 | return snk(chunk, err) |
| 69 | end | 69 | end |
| 70 | 70 | ||
| 71 | function metat.__index:send(data) | 71 | function metat.__index:send(data) |
| 72 | return self.control:send(data) | 72 | return self.c:send(data) |
| 73 | end | 73 | end |
| 74 | 74 | ||
| 75 | function metat.__index:receive(pat) | 75 | function metat.__index:receive(pat) |
| 76 | return self.control:receive(pat) | 76 | return self.c:receive(pat) |
| 77 | end | 77 | end |
| 78 | 78 | ||
| 79 | function metat.__index:getfd() | 79 | function metat.__index:getfd() |
| 80 | return self.control:getfd() | 80 | return self.c:getfd() |
| 81 | end | 81 | end |
| 82 | 82 | ||
| 83 | function metat.__index:dirty() | 83 | function metat.__index:dirty() |
| 84 | return self.control:dirty() | 84 | return self.c:dirty() |
| 85 | end | 85 | end |
| 86 | 86 | ||
| 87 | function metat.__index:getcontrol() | 87 | function metat.__index:getcontrol() |
| 88 | return self.control | 88 | return self.c |
| 89 | end | 89 | end |
| 90 | 90 | ||
| 91 | function metat.__index:source(source, step) | 91 | function metat.__index:source(source, step) |
| 92 | local sink = socket.sink("keep-open", self.control) | 92 | local sink = socket.sink("keep-open", self.c) |
| 93 | return ltn12.pump.all(source, sink, step or ltn12.pump.step) | 93 | return ltn12.pump.all(source, sink, step or ltn12.pump.step) |
| 94 | end | 94 | end |
| 95 | 95 | ||
| 96 | -- closes the underlying control | 96 | -- closes the underlying c |
| 97 | function metat.__index:close() | 97 | function metat.__index:close() |
| 98 | self.control:close() | 98 | self.c:close() |
| 99 | return 1 | 99 | return 1 |
| 100 | end | 100 | end |
| 101 | 101 | ||
| 102 | -- connect with server and return control object | 102 | -- connect with server and return c object |
| 103 | connect = socket.protect(function(host, port, timeout) | 103 | function connect(host, port, timeout) |
| 104 | local control = socket.try(socket.tcp()) | 104 | local c, e = socket.tcp() |
| 105 | socket.try(control:settimeout(timeout or TIMEOUT)) | 105 | if not c then return nil, e end |
| 106 | socket.try(control:connect(host, port)) | 106 | c:settimeout(timeout or TIMEOUT) |
| 107 | return setmetatable({control = control}, metat) | 107 | local r, e = c:connect(host, port) |
| 108 | end) | 108 | if not r then |
| 109 | c:close() | ||
| 110 | return nil, e | ||
| 111 | end | ||
| 112 | return setmetatable({c = c}, metat) | ||
| 113 | end | ||
diff --git a/test/httptest.lua b/test/httptest.lua index 45d7e8d..0ba6f56 100644 --- a/test/httptest.lua +++ b/test/httptest.lua | |||
| @@ -155,14 +155,15 @@ check_request(request, expect, ignore) | |||
| 155 | io.write("testing simple post function: ") | 155 | io.write("testing simple post function: ") |
| 156 | back = http.request("http://" .. host .. cgiprefix .. "/cat", index) | 156 | back = http.request("http://" .. host .. cgiprefix .. "/cat", index) |
| 157 | assert(back == index) | 157 | assert(back == index) |
| 158 | print("ok") | ||
| 158 | 159 | ||
| 159 | ------------------------------------------------------------------------ | 160 | ------------------------------------------------------------------------ |
| 160 | io.write("testing ltn12.(sink|source).file: ") | 161 | io.write("testing ltn12.(sink|source).file: ") |
| 161 | request = { | 162 | request = { |
| 162 | url = "http://" .. host .. cgiprefix .. "/cat", | 163 | url = "http://" .. host .. cgiprefix .. "/cat", |
| 163 | method = "POST", | 164 | method = "POST", |
| 164 | source = ltn12.source.file(io.open(index_file, "r")), | 165 | source = ltn12.source.file(io.open(index_file, "rb")), |
| 165 | sink = ltn12.sink.file(io.open(index_file .. "-back", "w")), | 166 | sink = ltn12.sink.file(io.open(index_file .. "-back", "wb")), |
| 166 | headers = { ["content-length"] = string.len(index) } | 167 | headers = { ["content-length"] = string.len(index) } |
| 167 | } | 168 | } |
| 168 | expect = { | 169 | expect = { |
| @@ -187,7 +188,7 @@ local function b64length(len) | |||
| 187 | end | 188 | end |
| 188 | 189 | ||
| 189 | local source = ltn12.source.chain( | 190 | local source = ltn12.source.chain( |
| 190 | ltn12.source.file(io.open(index_file, "r")), | 191 | ltn12.source.file(io.open(index_file, "rb")), |
| 191 | ltn12.filter.chain( | 192 | ltn12.filter.chain( |
| 192 | mime.encode("base64"), | 193 | mime.encode("base64"), |
| 193 | mime.wrap("base64") | 194 | mime.wrap("base64") |
| @@ -196,7 +197,7 @@ local source = ltn12.source.chain( | |||
| 196 | 197 | ||
| 197 | local sink = ltn12.sink.chain( | 198 | local sink = ltn12.sink.chain( |
| 198 | mime.decode("base64"), | 199 | mime.decode("base64"), |
| 199 | ltn12.sink.file(io.open(index_file .. "-back", "w")) | 200 | ltn12.sink.file(io.open(index_file .. "-back", "wb")) |
| 200 | ) | 201 | ) |
| 201 | 202 | ||
| 202 | request = { | 203 | request = { |
diff --git a/test/testsrvr.lua b/test/testsrvr.lua index 6e786c8..5b842f1 100644 --- a/test/testsrvr.lua +++ b/test/testsrvr.lua | |||
| @@ -13,7 +13,6 @@ while 1 do | |||
| 13 | -- control:setoption("nodelay", true) | 13 | -- control:setoption("nodelay", true) |
| 14 | while 1 do | 14 | while 1 do |
| 15 | command, error = control:receive() | 15 | command, error = control:receive() |
| 16 | print(error) | ||
| 17 | if error then | 16 | if error then |
| 18 | control:close() | 17 | control:close() |
| 19 | print("server: closing connection...") | 18 | print("server: closing connection...") |
