aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2005-11-22 08:33:29 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2005-11-22 08:33:29 +0000
commitd55a5826e81136a9ecf65c4cd407152a56684dc2 (patch)
tree109ad44c75cee890ad5e98583e12b15b5e65a18e
parenta2b780bf7a78c66d54a248fa99b5fc862c12a127 (diff)
downloadluasocket-d55a5826e81136a9ecf65c4cd407152a56684dc2.tar.gz
luasocket-d55a5826e81136a9ecf65c4cd407152a56684dc2.tar.bz2
luasocket-d55a5826e81136a9ecf65c4cd407152a56684dc2.zip
Few tweaks in installation, some missing files, etc.
-rw-r--r--config2
-rw-r--r--doc/installation.html8
-rw-r--r--doc/socket.html7
-rw-r--r--etc/check-links.lua6
-rw-r--r--etc/dict.lua10
-rw-r--r--etc/dispatch.lua82
-rw-r--r--etc/eol.lua2
-rw-r--r--etc/forward.lua8
-rw-r--r--etc/get.lua26
-rw-r--r--etc/tftp.lua16
-rw-r--r--makefile31
-rw-r--r--makefile.dist6
-rw-r--r--samples/cddb.lua12
-rw-r--r--samples/echosrvr.lua6
-rw-r--r--samples/lpr.lua3
-rw-r--r--samples/tinyirc.lua10
-rw-r--r--src/ftp.lua26
-rw-r--r--src/http.lua32
-rw-r--r--src/ltn12.lua30
-rw-r--r--src/mbox.lua2
-rw-r--r--src/mime.lua14
-rw-r--r--src/smtp.lua42
-rw-r--r--src/socket.lua16
-rw-r--r--src/tp.lua20
-rw-r--r--src/url.lua50
-rw-r--r--src/usocket.c3
26 files changed, 232 insertions, 238 deletions
diff --git a/config b/config
index 255477b..0b2b492 100644
--- a/config
+++ b/config
@@ -27,7 +27,7 @@ COMPAT=compat-5.1r4
27# Top of your Lua installation 27# Top of your Lua installation
28# Relative paths will be inside the src tree 28# Relative paths will be inside the src tree
29# 29#
30INSTALL_TOP_LUA=share 30INSTALL_TOP_SHARE=share
31INSTALL_TOP_LIB=lib 31INSTALL_TOP_LIB=lib
32 32
33INSTALL_DATA=cp 33INSTALL_DATA=cp
diff --git a/doc/installation.html b/doc/installation.html
index c8eb5d9..f293de6 100644
--- a/doc/installation.html
+++ b/doc/installation.html
@@ -69,22 +69,22 @@ independent files. Let's call these directories <tt>&lt;LIB&gt;</tt>
69and <tt>&lt;SHARE&gt;</tt>, respectively. 69and <tt>&lt;SHARE&gt;</tt>, respectively.
70For instance, in my laptop, I use '<tt>/usr/local/lib/lua/5.0</tt>' for 70For instance, in my laptop, I use '<tt>/usr/local/lib/lua/5.0</tt>' for
71<tt>&lt;LIB&gt;</tt> and '<tt>/usr/local/share/lua/5.0</tt>' for 71<tt>&lt;LIB&gt;</tt> and '<tt>/usr/local/share/lua/5.0</tt>' for
72<tt>&lt;SHARE&gt;</tt>. On Windows, only one directory is used, say 72<tt>&lt;SHARE&gt;</tt>. On Windows, sometimes only one directory is used, say
73'<tt>c:\program files\lua\5.0</tt>'. Here is the standard LuaSocket 73'<tt>c:\program files\lua\5.0</tt>'. Here is the standard LuaSocket
74distribution directory structure:</p> 74distribution directory structure:</p>
75 75
76<pre class=example> 76<pre class=example>
77&lt;SHARE&gt;/compat-5.1.lua 77&lt;SHARE&gt;/compat-5.1.lua
78&lt;SHARE&gt;/ltn12.lua 78&lt;SHARE&gt;/ltn12.lua
79&lt;SHARE&gt;/mime/mime.lua 79&lt;SHARE&gt;/socket.lua
80&lt;LIB&gt;/mime/core.dll
81&lt;SHARE&gt;/socket/socket.lua
82&lt;LIB&gt;/socket/core.dll 80&lt;LIB&gt;/socket/core.dll
83&lt;SHARE&gt;/socket/http.lua 81&lt;SHARE&gt;/socket/http.lua
84&lt;SHARE&gt;/socket/tp.lua 82&lt;SHARE&gt;/socket/tp.lua
85&lt;SHARE&gt;/socket/ftp.lua 83&lt;SHARE&gt;/socket/ftp.lua
86&lt;SHARE&gt;/socket/smtp.lua 84&lt;SHARE&gt;/socket/smtp.lua
87&lt;SHARE&gt;/socket/url.lua 85&lt;SHARE&gt;/socket/url.lua
86&lt;SHARE&gt;/mime.lua
87&lt;LIB&gt;/mime/core.dll
88</pre> 88</pre>
89 89
90<p> Naturally, on Unix systems, <tt>core.dll</tt> 90<p> Naturally, on Unix systems, <tt>core.dll</tt>
diff --git a/doc/socket.html b/doc/socket.html
index 82e958a..d050a42 100644
--- a/doc/socket.html
+++ b/doc/socket.html
@@ -210,13 +210,6 @@ Use the <a href=tcp.html#settimeout><tt>settimeout</tt></a>
210method or <tt>accept</tt> might block forever. 210method or <tt>accept</tt> might block forever.
211</p> 211</p>
212 212
213<p class=note>
214Interesting note: as mentioned in some Unix manuals, calling select with both
215sets empty and a non-null timeout is a fairly portable way to sleep with
216sub-second precision (<b>except it doesn't work on Windows</b>).
217</p>
218
219
220<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 213<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
221 214
222<p class=name id=sink> 215<p class=name id=sink>
diff --git a/etc/check-links.lua b/etc/check-links.lua
index 725cd2a..a989f8c 100644
--- a/etc/check-links.lua
+++ b/etc/check-links.lua
@@ -37,7 +37,7 @@ function getstatus(link)
37 handler:start(function() 37 handler:start(function()
38 local r, c, h, s = http.request{ 38 local r, c, h, s = http.request{
39 method = "HEAD", 39 method = "HEAD",
40 url = link, 40 url = link,
41 create = handler.tcp 41 create = handler.tcp
42 } 42 }
43 if r and c == 200 then io.write('\t', link, '\n') 43 if r and c == 200 then io.write('\t', link, '\n')
@@ -107,6 +107,6 @@ for _, address in ipairs(arg) do
107 checklinks(url.absolute("file:", address)) 107 checklinks(url.absolute("file:", address))
108end 108end
109 109
110while nthreads > 0 do 110while nthreads > 0 do
111 handler:step() 111 handler:step()
112end 112end
diff --git a/etc/dict.lua b/etc/dict.lua
index 2d035a7..5c85aae 100644
--- a/etc/dict.lua
+++ b/etc/dict.lua
@@ -17,7 +17,7 @@ local tp = require("socket.tp")
17module("socket.dict") 17module("socket.dict")
18 18
19----------------------------------------------------------------------------- 19-----------------------------------------------------------------------------
20-- Globals 20-- Globals
21----------------------------------------------------------------------------- 21-----------------------------------------------------------------------------
22HOST = "dict.org" 22HOST = "dict.org"
23PORT = 2628 23PORT = 2628
@@ -39,7 +39,7 @@ end
39 39
40function metat.__index:check(ok) 40function metat.__index:check(ok)
41 local code, status = socket.try(self.tp:check(ok)) 41 local code, status = socket.try(self.tp:check(ok))
42 return code, 42 return code,
43 base.tonumber(socket.skip(2, string.find(status, "^%d%d%d (%d*)"))) 43 base.tonumber(socket.skip(2, string.find(status, "^%d%d%d (%d*)")))
44end 44end
45 45
@@ -101,7 +101,7 @@ local default = {
101} 101}
102 102
103local function there(f) 103local function there(f)
104 if f == "" then return nil 104 if f == "" then return nil
105 else return f end 105 else return f end
106end 106end
107 107
@@ -116,7 +116,7 @@ local function parse(u)
116 arg = string.gsub(arg, "^:([^:]+)", function(f) t.word = f end) 116 arg = string.gsub(arg, "^:([^:]+)", function(f) t.word = f end)
117 socket.try(t.word, "need at least <word> in URL") 117 socket.try(t.word, "need at least <word> in URL")
118 arg = string.gsub(arg, "^:([^:]*)", function(f) t.database = there(f) end) 118 arg = string.gsub(arg, "^:([^:]*)", function(f) t.database = there(f) end)
119 if cmd == "m" then 119 if cmd == "m" then
120 arg = string.gsub(arg, "^:([^:]*)", function(f) t.strat = there(f) end) 120 arg = string.gsub(arg, "^:([^:]*)", function(f) t.strat = there(f) end)
121 end 121 end
122 string.gsub(arg, ":([^:]*)$", function(f) t.n = base.tonumber(f) end) 122 string.gsub(arg, ":([^:]*)$", function(f) t.n = base.tonumber(f) end)
@@ -130,7 +130,7 @@ local function tget(gett)
130 local def = con:define(gett.database, gett.word) 130 local def = con:define(gett.database, gett.word)
131 con:quit() 131 con:quit()
132 con:close() 132 con:close()
133 if gett.n then return def[gett.n] 133 if gett.n then return def[gett.n]
134 else return def end 134 else return def end
135 elseif gett.command == "m" then 135 elseif gett.command == "m" then
136 local mat = con:match(gett.database, gett.strat, gett.word) 136 local mat = con:match(gett.database, gett.strat, gett.word)
diff --git a/etc/dispatch.lua b/etc/dispatch.lua
index 98fa8a8..dd76d6d 100644
--- a/etc/dispatch.lua
+++ b/etc/dispatch.lua
@@ -14,7 +14,7 @@ module("dispatch")
14TIMEOUT = 60 14TIMEOUT = 60
15 15
16----------------------------------------------------------------------------- 16-----------------------------------------------------------------------------
17-- We implement 3 types of dispatchers: 17-- We implement 3 types of dispatchers:
18-- sequential 18-- sequential
19-- coroutine 19-- coroutine
20-- threaded 20-- threaded
@@ -34,7 +34,7 @@ end
34 34
35-- sequential handler simply calls the functions and doesn't wrap I/O 35-- sequential handler simply calls the functions and doesn't wrap I/O
36function handlert.sequential() 36function handlert.sequential()
37 return { 37 return {
38 tcp = socket.tcp, 38 tcp = socket.tcp,
39 start = seqstart 39 start = seqstart
40 } 40 }
@@ -55,7 +55,7 @@ function socket.protect(f)
55 if not status then 55 if not status then
56 if type(results[1]) == 'table' then 56 if type(results[1]) == 'table' then
57 return nil, results[1][1] 57 return nil, results[1][1]
58 else error(results[1]) end 58 else error(results[1]) end
59 end 59 end
60 if coroutine.status(co) == "suspended" then 60 if coroutine.status(co) == "suspended" then
61 arg = {coroutine.yield(unpack(results))} 61 arg = {coroutine.yield(unpack(results))}
@@ -84,17 +84,17 @@ local function newset()
84 if index then 84 if index then
85 reverse[value] = nil 85 reverse[value] = nil
86 local top = table.remove(set) 86 local top = table.remove(set)
87 if top ~= value then 87 if top ~= value then
88 reverse[top] = index 88 reverse[top] = index
89 set[index] = top 89 set[index] = top
90 end 90 end
91 end 91 end
92 end 92 end
93 }}) 93 }})
94end 94end
95 95
96----------------------------------------------------------------------------- 96-----------------------------------------------------------------------------
97-- socket.tcp() wrapper for the coroutine dispatcher 97-- socket.tcp() wrapper for the coroutine dispatcher
98----------------------------------------------------------------------------- 98-----------------------------------------------------------------------------
99local function cowrap(dispatcher, tcp, error) 99local function cowrap(dispatcher, tcp, error)
100 if not tcp then return nil, error end 100 if not tcp then return nil, error end
@@ -102,7 +102,7 @@ local function cowrap(dispatcher, tcp, error)
102 tcp:settimeout(0) 102 tcp:settimeout(0)
103 -- metatable for wrap produces new methods on demand for those that we 103 -- metatable for wrap produces new methods on demand for those that we
104 -- don't override explicitly. 104 -- don't override explicitly.
105 local metat = { __index = function(table, key) 105 local metat = { __index = function(table, key)
106 table[key] = function(...) 106 table[key] = function(...)
107 arg[1] = tcp 107 arg[1] = tcp
108 return tcp[key](unpack(arg)) 108 return tcp[key](unpack(arg))
@@ -112,7 +112,7 @@ local function cowrap(dispatcher, tcp, error)
112 -- does our user want to do his own non-blocking I/O? 112 -- does our user want to do his own non-blocking I/O?
113 local zero = false 113 local zero = false
114 -- create a wrap object that will behave just like a real socket object 114 -- create a wrap object that will behave just like a real socket object
115 local wrap = { } 115 local wrap = { }
116 -- we ignore settimeout to preserve our 0 timeout, but record whether 116 -- we ignore settimeout to preserve our 0 timeout, but record whether
117 -- the user wants to do his own non-blocking I/O 117 -- the user wants to do his own non-blocking I/O
118 function wrap:settimeout(value, mode) 118 function wrap:settimeout(value, mode)
@@ -121,19 +121,19 @@ local function cowrap(dispatcher, tcp, error)
121 return 1 121 return 1
122 end 122 end
123 -- send in non-blocking mode and yield on timeout 123 -- send in non-blocking mode and yield on timeout
124 function wrap:send(data, first, last) 124 function wrap:send(data, first, last)
125 first = (first or 1) - 1 125 first = (first or 1) - 1
126 local result, error 126 local result, error
127 while true do 127 while true do
128 -- return control to dispatcher and tell it we want to send 128 -- return control to dispatcher and tell it we want to send
129 -- if upon return the dispatcher tells us we timed out, 129 -- if upon return the dispatcher tells us we timed out,
130 -- return an error to whoever called us 130 -- return an error to whoever called us
131 if coroutine.yield(dispatcher.sending, tcp) == "timeout" then 131 if coroutine.yield(dispatcher.sending, tcp) == "timeout" then
132 return nil, "timeout" 132 return nil, "timeout"
133 end 133 end
134 -- try sending 134 -- try sending
135 result, error, first = tcp:send(data, first+1, last) 135 result, error, first = tcp:send(data, first+1, last)
136 -- if we are done, or there was an unexpected error, 136 -- if we are done, or there was an unexpected error,
137 -- break away from loop 137 -- break away from loop
138 if error ~= "timeout" then return result, error, first end 138 if error ~= "timeout" then return result, error, first end
139 end 139 end
@@ -143,20 +143,20 @@ local function cowrap(dispatcher, tcp, error)
143 function wrap:receive(pattern, partial) 143 function wrap:receive(pattern, partial)
144 local error = "timeout" 144 local error = "timeout"
145 local value 145 local value
146 while true do 146 while true do
147 -- return control to dispatcher and tell it we want to receive 147 -- return control to dispatcher and tell it we want to receive
148 -- if upon return the dispatcher tells us we timed out, 148 -- if upon return the dispatcher tells us we timed out,
149 -- return an error to whoever called us 149 -- return an error to whoever called us
150 if coroutine.yield(dispatcher.receiving, tcp) == "timeout" then 150 if coroutine.yield(dispatcher.receiving, tcp) == "timeout" then
151 return nil, "timeout" 151 return nil, "timeout"
152 end 152 end
153 -- try receiving 153 -- try receiving
154 value, error, partial = tcp:receive(pattern, partial) 154 value, error, partial = tcp:receive(pattern, partial)
155 -- if we are done, or there was an unexpected error, 155 -- if we are done, or there was an unexpected error,
156 -- break away from loop. also, if the user requested 156 -- break away from loop. also, if the user requested
157 -- zero timeout, return all we got 157 -- zero timeout, return all we got
158 if (error ~= "timeout") or zero then 158 if (error ~= "timeout") or zero then
159 return value, error, partial 159 return value, error, partial
160 end 160 end
161 end 161 end
162 end 162 end
@@ -168,8 +168,8 @@ local function cowrap(dispatcher, tcp, error)
168 -- connection succeeds. 168 -- connection succeeds.
169 -- if upon return the dispatcher tells us we have a 169 -- if upon return the dispatcher tells us we have a
170 -- timeout, just abort 170 -- timeout, just abort
171 if coroutine.yield(dispatcher.sending, tcp) == "timeout" then 171 if coroutine.yield(dispatcher.sending, tcp) == "timeout" then
172 return nil, "timeout" 172 return nil, "timeout"
173 end 173 end
174 -- when we come back, check if connection was successful 174 -- when we come back, check if connection was successful
175 result, error = tcp:connect(host, port) 175 result, error = tcp:connect(host, port)
@@ -179,27 +179,27 @@ local function cowrap(dispatcher, tcp, error)
179 end 179 end
180 -- accept in non-blocking mode and yield on timeout 180 -- accept in non-blocking mode and yield on timeout
181 function wrap:accept() 181 function wrap:accept()
182 while 1 do 182 while 1 do
183 -- return control to dispatcher. we will be readable when a 183 -- return control to dispatcher. we will be readable when a
184 -- connection arrives. 184 -- connection arrives.
185 -- if upon return the dispatcher tells us we have a 185 -- if upon return the dispatcher tells us we have a
186 -- timeout, just abort 186 -- timeout, just abort
187 if coroutine.yield(dispatcher.receiving, tcp) == "timeout" then 187 if coroutine.yield(dispatcher.receiving, tcp) == "timeout" then
188 return nil, "timeout" 188 return nil, "timeout"
189 end 189 end
190 local client, error = tcp:accept() 190 local client, error = tcp:accept()
191 if error ~= "timeout" then 191 if error ~= "timeout" then
192 return cowrap(dispatcher, client, error) 192 return cowrap(dispatcher, client, error)
193 end 193 end
194 end 194 end
195 end 195 end
196 -- remove cortn from context 196 -- remove cortn from context
197 function wrap:close() 197 function wrap:close()
198 dispatcher.stamp[tcp] = nil 198 dispatcher.stamp[tcp] = nil
199 dispatcher.sending.set:remove(tcp) 199 dispatcher.sending.set:remove(tcp)
200 dispatcher.sending.cortn[tcp] = nil 200 dispatcher.sending.cortn[tcp] = nil
201 dispatcher.receiving.set:remove(tcp) 201 dispatcher.receiving.set:remove(tcp)
202 dispatcher.receiving.cortn[tcp] = nil 202 dispatcher.receiving.cortn[tcp] = nil
203 return tcp:close() 203 return tcp:close()
204 end 204 end
205 return setmetatable(wrap, metat) 205 return setmetatable(wrap, metat)
@@ -207,12 +207,12 @@ end
207 207
208 208
209----------------------------------------------------------------------------- 209-----------------------------------------------------------------------------
210-- Our coroutine dispatcher 210-- Our coroutine dispatcher
211----------------------------------------------------------------------------- 211-----------------------------------------------------------------------------
212local cometat = { __index = {} } 212local cometat = { __index = {} }
213 213
214function schedule(cortn, status, operation, tcp) 214function schedule(cortn, status, operation, tcp)
215 if status then 215 if status then
216 if cortn and operation then 216 if cortn and operation then
217 operation.set:insert(tcp) 217 operation.set:insert(tcp)
218 operation.cortn[tcp] = cortn 218 operation.cortn[tcp] = cortn
@@ -233,7 +233,7 @@ function wakeup(operation, tcp)
233 kick(operation, tcp) 233 kick(operation, tcp)
234 return cortn, coroutine.resume(cortn) 234 return cortn, coroutine.resume(cortn)
235 -- othrewise, just get scheduler not to do anything 235 -- othrewise, just get scheduler not to do anything
236 else 236 else
237 return nil, true 237 return nil, true
238 end 238 end
239end 239end
@@ -249,7 +249,7 @@ end
249-- step through all active cortns 249-- step through all active cortns
250function cometat.__index:step() 250function cometat.__index:step()
251 -- check which sockets are interesting and act on them 251 -- check which sockets are interesting and act on them
252 local readable, writable = socket.select(self.receiving.set, 252 local readable, writable = socket.select(self.receiving.set,
253 self.sending.set, 1) 253 self.sending.set, 1)
254 -- for all readable connections, resume their cortns and reschedule 254 -- for all readable connections, resume their cortns and reschedule
255 -- when they yield back to us 255 -- when they yield back to us
@@ -260,7 +260,7 @@ function cometat.__index:step()
260 for _, tcp in ipairs(writable) do 260 for _, tcp in ipairs(writable) do
261 schedule(wakeup(self.sending, tcp)) 261 schedule(wakeup(self.sending, tcp))
262 end 262 end
263 -- politely ask replacement I/O functions in idle cortns to 263 -- politely ask replacement I/O functions in idle cortns to
264 -- return reporting a timeout 264 -- return reporting a timeout
265 local now = socket.gettime() 265 local now = socket.gettime()
266 for tcp, stamp in pairs(self.stamp) do 266 for tcp, stamp in pairs(self.stamp) do
@@ -271,25 +271,25 @@ function cometat.__index:step()
271 end 271 end
272end 272end
273 273
274function cometat.__index:start(func) 274function cometat.__index:start(func)
275 local cortn = coroutine.create(func) 275 local cortn = coroutine.create(func)
276 schedule(cortn, coroutine.resume(cortn)) 276 schedule(cortn, coroutine.resume(cortn))
277end 277end
278 278
279function handlert.coroutine() 279function handlert.coroutine()
280 local stamp = {} 280 local stamp = {}
281 local dispatcher = { 281 local dispatcher = {
282 stamp = stamp, 282 stamp = stamp,
283 sending = { 283 sending = {
284 name = "sending", 284 name = "sending",
285 set = newset(), 285 set = newset(),
286 cortn = {}, 286 cortn = {},
287 stamp = stamp 287 stamp = stamp
288 }, 288 },
289 receiving = { 289 receiving = {
290 name = "receiving", 290 name = "receiving",
291 set = newset(), 291 set = newset(),
292 cortn = {}, 292 cortn = {},
293 stamp = stamp 293 stamp = stamp
294 }, 294 },
295 } 295 }
diff --git a/etc/eol.lua b/etc/eol.lua
index 01dba67..d7c5db6 100644
--- a/etc/eol.lua
+++ b/etc/eol.lua
@@ -1,5 +1,5 @@
1----------------------------------------------------------------------------- 1-----------------------------------------------------------------------------
2-- Little program to adjust end of line markers. 2-- Little program to adjust end of line markers.
3-- LuaSocket sample files 3-- LuaSocket sample files
4-- Author: Diego Nehab 4-- Author: Diego Nehab
5-- RCS ID: $Id$ 5-- RCS ID: $Id$
diff --git a/etc/forward.lua b/etc/forward.lua
index eac98ae..9073ac4 100644
--- a/etc/forward.lua
+++ b/etc/forward.lua
@@ -17,10 +17,10 @@ local function move(foo, bar)
17 live = data or error == "timeout" 17 live = data or error == "timeout"
18 data = data or partial 18 data = data or partial
19 local result, error = bar:send(data) 19 local result, error = bar:send(data)
20 if not live or not result then 20 if not live or not result then
21 foo:close() 21 foo:close()
22 bar:close() 22 bar:close()
23 break 23 break
24 end 24 end
25 end 25 end
26end 26end
@@ -51,7 +51,7 @@ for i, v in ipairs(arg) do
51 handler:start(function() 51 handler:start(function()
52 move(client, peer) 52 move(client, peer)
53 end) 53 end)
54 -- afte starting new handler, enter in loop sending data from 54 -- afte starting new handler, enter in loop sending data from
55 -- peer to client 55 -- peer to client
56 move(peer, client) 56 move(peer, client)
57 end) 57 end)
diff --git a/etc/get.lua b/etc/get.lua
index 0c95d54..ebf3e75 100644
--- a/etc/get.lua
+++ b/etc/get.lua
@@ -53,10 +53,10 @@ local elapsed_s = "%s received, %s/s throughput, %s elapsed "
53function gauge(got, delta, size) 53function gauge(got, delta, size)
54 local rate = got / delta 54 local rate = got / delta
55 if size and size >= 1 then 55 if size and size >= 1 then
56 return string.format(remaining_s, nicesize(got), nicesize(rate), 56 return string.format(remaining_s, nicesize(got), nicesize(rate),
57 100*got/size, nicetime((size-got)/rate)) 57 100*got/size, nicetime((size-got)/rate))
58 else 58 else
59 return string.format(elapsed_s, nicesize(got), 59 return string.format(elapsed_s, nicesize(got),
60 nicesize(rate), nicetime(delta)) 60 nicesize(rate), nicetime(delta))
61 end 61 end
62end 62end
@@ -68,18 +68,18 @@ function stats(size)
68 local got = 0 68 local got = 0
69 return function(chunk) 69 return function(chunk)
70 -- elapsed time since start 70 -- elapsed time since start
71 local delta = socket.gettime() - start 71 local delta = socket.gettime() - start
72 if chunk then 72 if chunk then
73 -- total bytes received 73 -- total bytes received
74 got = got + string.len(chunk) 74 got = got + string.len(chunk)
75 -- not enough time for estimate 75 -- not enough time for estimate
76 if delta > 0.1 then 76 if delta > 0.1 then
77 io.stderr:write("\r", gauge(got, delta, size)) 77 io.stderr:write("\r", gauge(got, delta, size))
78 io.stderr:flush() 78 io.stderr:flush()
79 end 79 end
80 else 80 else
81 -- close up 81 -- close up
82 io.stderr:write("\r", gauge(got, delta), "\n") 82 io.stderr:write("\r", gauge(got, delta), "\n")
83 end 83 end
84 return chunk 84 return chunk
85 end 85 end
@@ -111,11 +111,11 @@ function getbyftp(u, file)
111 local gett = url.parse(u) 111 local gett = url.parse(u)
112 gett.sink = save 112 gett.sink = save
113 gett.type = "i" 113 gett.type = "i"
114 local ret, err = ftp.get(gett) 114 local ret, err = ftp.get(gett)
115 if err then print(err) end 115 if err then print(err) end
116end 116end
117 117
118-- determines the scheme 118-- determines the scheme
119function getscheme(u) 119function getscheme(u)
120 -- this is an heuristic to solve a common invalid url poblem 120 -- this is an heuristic to solve a common invalid url poblem
121 if not string.find(u, "//") then u = "//" .. u end 121 if not string.find(u, "//") then u = "//" .. u end
@@ -134,7 +134,7 @@ end
134 134
135-- main program 135-- main program
136arg = arg or {} 136arg = arg or {}
137if table.getn(arg) < 1 then 137if table.getn(arg) < 1 then
138 io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n") 138 io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
139 os.exit(1) 139 os.exit(1)
140else get(arg[1], arg[2]) end 140else get(arg[1], arg[2]) end
diff --git a/etc/tftp.lua b/etc/tftp.lua
index 1b589fb..c028b20 100644
--- a/etc/tftp.lua
+++ b/etc/tftp.lua
@@ -46,7 +46,7 @@ local function ACK(block)
46 local low, high 46 local low, high
47 low = math.mod(block, 256) 47 low = math.mod(block, 256)
48 high = (block - low)/256 48 high = (block - low)/256
49 return char(0, OP_ACK, high, low) 49 return char(0, OP_ACK, high, low)
50end 50end
51 51
52local function get_OP(dgram) 52local function get_OP(dgram)
@@ -71,7 +71,7 @@ local function get_ERROR(dgram)
71end 71end
72 72
73----------------------------------------------------------------------------- 73-----------------------------------------------------------------------------
74-- The real work 74-- The real work
75----------------------------------------------------------------------------- 75-----------------------------------------------------------------------------
76local function tget(gett) 76local function tget(gett)
77 local retries, dgram, sent, datahost, dataport, code 77 local retries, dgram, sent, datahost, dataport, code
@@ -83,15 +83,15 @@ local function tget(gett)
83 gett.host = try(socket.dns.toip(gett.host)) 83 gett.host = try(socket.dns.toip(gett.host))
84 con:settimeout(1) 84 con:settimeout(1)
85 -- first packet gives data host/port to be used for data transfers 85 -- first packet gives data host/port to be used for data transfers
86 local path = string.gsub(gett.path or "", "^/", "") 86 local path = string.gsub(gett.path or "", "^/", "")
87 path = url.unescape(path) 87 path = url.unescape(path)
88 retries = 0 88 retries = 0
89 repeat 89 repeat
90 sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port)) 90 sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port))
91 dgram, datahost, dataport = con:receivefrom() 91 dgram, datahost, dataport = con:receivefrom()
92 retries = retries + 1 92 retries = retries + 1
93 until dgram or datahost ~= "timeout" or retries > 5 93 until dgram or datahost ~= "timeout" or retries > 5
94 try(dgram, datahost) 94 try(dgram, datahost)
95 -- associate socket with data host/port 95 -- associate socket with data host/port
96 try(con:setpeername(datahost, dataport)) 96 try(con:setpeername(datahost, dataport))
97 -- default sink 97 -- default sink
@@ -110,7 +110,7 @@ local function tget(gett)
110 last = block 110 last = block
111 end 111 end
112 -- last packet brings less than 512 bytes of data 112 -- last packet brings less than 512 bytes of data
113 if string.len(data) < 512 then 113 if string.len(data) < 512 then
114 try(con:send(ACK(block))) 114 try(con:send(ACK(block)))
115 try(con:close()) 115 try(con:close())
116 try(sink(nil)) 116 try(sink(nil))
@@ -118,7 +118,7 @@ local function tget(gett)
118 end 118 end
119 -- get the next packet 119 -- get the next packet
120 retries = 0 120 retries = 0
121 repeat 121 repeat
122 sent = try(con:send(ACK(last))) 122 sent = try(con:send(ACK(last)))
123 dgram, err = con:receive() 123 dgram, err = con:receive()
124 retries = retries + 1 124 retries = retries + 1
@@ -141,7 +141,7 @@ local function parse(u)
141end 141end
142 142
143local function sget(u) 143local function sget(u)
144 local gett = parse(u) 144 local gett = parse(u)
145 local t = {} 145 local t = {}
146 gett.sink = ltn12.sink.table(t) 146 gett.sink = ltn12.sink.table(t)
147 tget(gett) 147 tget(gett)
diff --git a/makefile b/makefile
index c84ef10..f77bde5 100644
--- a/makefile
+++ b/makefile
@@ -6,9 +6,9 @@ include config
6#------ 6#------
7# Hopefully no need to change anything below this line 7# Hopefully no need to change anything below this line
8# 8#
9INSTALL_SOCKET_LUA=$(INSTALL_TOP_LUA)/socket 9INSTALL_SOCKET_SHARE=$(INSTALL_TOP_SHARE)/socket
10INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket 10INSTALL_SOCKET_LIB=$(INSTALL_TOP_LIB)/socket
11INSTALL_MIME_LUA=$(INSTALL_TOP_LUA)/mime 11INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime
12INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime 12INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime
13 13
14all clean: 14all clean:
@@ -17,35 +17,34 @@ all clean:
17#------ 17#------
18# Files to install 18# Files to install
19# 19#
20TO_SOCKET_LUA:= \ 20TO_SOCKET_SHARE:= \
21 socket.lua \
22 http.lua \ 21 http.lua \
23 url.lua \ 22 url.lua \
24 tp.lua \ 23 tp.lua \
25 ftp.lua \ 24 ftp.lua \
26 smtp.lua 25 smtp.lua
27 26
28TO_TOP_LUA:= \ 27TO_TOP_SHARE:= \
29 ltn12.lua 28 $(COMPAT)/compat-5.1.lua \
30 29 ltn12.lua \
31TO_MIME_LUA:= \ 30 socket.lua \
32 mime.lua 31 mime.lua
33 32
33TO_MIME_SHARE:=
34
34#------ 35#------
35# Install LuaSocket according to recommendation 36# Install LuaSocket according to recommendation
36# 37#
37install: all 38install: all
38 cd src; mkdir -p $(INSTALL_TOP_LUA) 39 cd src; mkdir -p $(INSTALL_TOP_SHARE)
39 cd src; mkdir -p $(INSTALL_TOP_LIB) 40 cd src; $(INSTALL_DATA) $(TO_TOP_SHARE) $(INSTALL_TOP_SHARE)
40 cd src; $(INSTALL_DATA) $(COMPAT)/compat-5.1.lua $(INSTALL_TOP_LUA) 41 cd src; mkdir -p $(INSTALL_SOCKET_SHARE)
41 cd src; $(INSTALL_DATA) ltn12.lua $(INSTALL_TOP_LUA) 42 cd src; $(INSTALL_DATA) $(TO_SOCKET_SHARE) $(INSTALL_SOCKET_SHARE)
42 cd src; mkdir -p $(INSTALL_SOCKET_LUA)
43 cd src; mkdir -p $(INSTALL_SOCKET_LIB) 43 cd src; mkdir -p $(INSTALL_SOCKET_LIB)
44 cd src; $(INSTALL_DATA) $(TO_SOCKET_LUA) $(INSTALL_SOCKET_LUA)
45 cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(EXT) 44 cd src; $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(EXT)
46 cd src; mkdir -p $(INSTALL_MIME_LUA) 45 #cd src; mkdir -p $(INSTALL_MIME_SHARE)
46 #cd src; $(INSTALL_DATA) $(TO_MIME_SHARE) $(INSTALL_MIME_SHARE)
47 cd src; mkdir -p $(INSTALL_MIME_LIB) 47 cd src; mkdir -p $(INSTALL_MIME_LIB)
48 cd src; $(INSTALL_DATA) $(TO_MIME_LUA) $(INSTALL_MIME_LUA)
49 cd src; $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(EXT) 48 cd src; $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(EXT)
50 49
51#------ 50#------
diff --git a/makefile.dist b/makefile.dist
index 54a9751..aefb41c 100644
--- a/makefile.dist
+++ b/makefile.dist
@@ -1,13 +1,12 @@
1#-------------------------------------------------------------------------- 1#--------------------------------------------------------------------------
2# Distribution makefile 2# Distribution makefile
3#-------------------------------------------------------------------------- 3#--------------------------------------------------------------------------
4
5DIST = luasocket-2.0 4DIST = luasocket-2.0
6 5
7COMPAT = src/compat-5.1r4 6COMPAT = src/compat-5.1r4
8 7
9
10TEST = \ 8TEST = \
9 test/README \
11 test/testclnt.lua \ 10 test/testclnt.lua \
12 test/testsrvr.lua \ 11 test/testsrvr.lua \
13 test/testsupport.lua 12 test/testsupport.lua
@@ -33,12 +32,12 @@ ETC = \
33 etc/eol.lua \ 32 etc/eol.lua \
34 etc/forward.lua \ 33 etc/forward.lua \
35 etc/get.lua \ 34 etc/get.lua \
36 etc/links \
37 etc/lp.lua \ 35 etc/lp.lua \
38 etc/qp.lua \ 36 etc/qp.lua \
39 etc/tftp.lua 37 etc/tftp.lua
40 38
41SRC = \ 39SRC = \
40 src/makefile \
42 src/auxiliar.c \ 41 src/auxiliar.c \
43 src/auxiliar.h \ 42 src/auxiliar.h \
44 src/buffer.c \ 43 src/buffer.c \
@@ -108,6 +107,7 @@ dist:
108 mkdir -p $(DIST) 107 mkdir -p $(DIST)
109 cp -vf NEW $(DIST) 108 cp -vf NEW $(DIST)
110 cp -vf LICENSE $(DIST) 109 cp -vf LICENSE $(DIST)
110 cp -vf README $(DIST)
111 cp -vf $(MAKE) $(DIST) 111 cp -vf $(MAKE) $(DIST)
112 112
113 mkdir -p $(DIST)/etc 113 mkdir -p $(DIST)/etc
diff --git a/samples/cddb.lua b/samples/cddb.lua
index 482dc98..883730c 100644
--- a/samples/cddb.lua
+++ b/samples/cddb.lua
@@ -16,7 +16,7 @@ function parse(body)
16 return nil, code, message 16 return nil, code, message
17 end 17 end
18 local data = {} 18 local data = {}
19 for l in lines do 19 for l in lines do
20 local c = string.sub(l, 1, 1) 20 local c = string.sub(l, 1, 1)
21 if c ~= '#' and c ~= '.' then 21 if c ~= '#' and c ~= '.' then
22 local key, value = socket.skip(2, string.find(l, "(.-)=(.*)")) 22 local key, value = socket.skip(2, string.find(l, "(.-)=(.*)"))
@@ -26,7 +26,7 @@ function parse(body)
26 data[key] = value 26 data[key] = value
27 end 27 end
28 end 28 end
29 return data, code, message 29 return data, code, message
30end 30end
31 31
32local host = socket.dns.gethostname() 32local host = socket.dns.gethostname()
@@ -34,13 +34,13 @@ local query = "%s?cmd=cddb+read+%s+%s&hello=LuaSocket+%s+LuaSocket+2.0&proto=6"
34local url = string.format(query, server, arg[1], arg[2], host) 34local url = string.format(query, server, arg[1], arg[2], host)
35local body, headers, code = http.get(url) 35local body, headers, code = http.get(url)
36 36
37if code == 200 then 37if code == 200 then
38 local data, code, error = parse(body) 38 local data, code, error = parse(body)
39 if not data then 39 if not data then
40 print(error or code) 40 print(error or code)
41 else 41 else
42 for i,v in pairs(data) do 42 for i,v in pairs(data) do
43 io.write(i, ': ', v, '\n') 43 io.write(i, ': ', v, '\n')
44 end 44 end
45 end 45 end
46else print(error) end 46else print(error) end
diff --git a/samples/echosrvr.lua b/samples/echosrvr.lua
index d4449e5..8d39ed9 100644
--- a/samples/echosrvr.lua
+++ b/samples/echosrvr.lua
@@ -20,10 +20,10 @@ assert(ip, port)
20print("Waiting packets on " .. ip .. ":" .. port .. "...") 20print("Waiting packets on " .. ip .. ":" .. port .. "...")
21while 1 do 21while 1 do
22 dgram, ip, port = udp:receivefrom() 22 dgram, ip, port = udp:receivefrom()
23 if dgram then 23 if dgram then
24 print("Echoing '" .. dgram .. "' to " .. ip .. ":" .. port) 24 print("Echoing '" .. dgram .. "' to " .. ip .. ":" .. port)
25 udp:sendto(dgram, ip, port) 25 udp:sendto(dgram, ip, port)
26 else 26 else
27 print(ip) 27 print(ip)
28 end 28 end
29end 29end
diff --git a/samples/lpr.lua b/samples/lpr.lua
index 5ab4d69..2b059b1 100644
--- a/samples/lpr.lua
+++ b/samples/lpr.lua
@@ -36,7 +36,8 @@ do
36 return usage() 36 return usage()
37 end 37 end
38 if arg[1] ~= "query" then 38 if arg[1] ~= "query" then
39 r,e=lp.send(arg[1],opt) 39 opt.file = arg[1]
40 r,e=lp.send(opt)
40 io.stdout:write(tostring(r or e),'\n') 41 io.stdout:write(tostring(r or e),'\n')
41 else 42 else
42 r,e=lp.query(opt) 43 r,e=lp.query(opt)
diff --git a/samples/tinyirc.lua b/samples/tinyirc.lua
index e3dd517..dd2c6f8 100644
--- a/samples/tinyirc.lua
+++ b/samples/tinyirc.lua
@@ -62,24 +62,24 @@ while 1 do
62 if input == server1 or input == server2 then 62 if input == server1 or input == server2 then
63 io.write("Waiting for clients\n") 63 io.write("Waiting for clients\n")
64 local new = input:accept() 64 local new = input:accept()
65 if new then 65 if new then
66 new:settimeout(1) 66 new:settimeout(1)
67 io.write("Inserting client in set\n") 67 io.write("Inserting client in set\n")
68 set:insert(new) 68 set:insert(new)
69 end 69 end
70 -- it is a client socket 70 -- it is a client socket
71 else 71 else
72 local line, error = input:receive() 72 local line, error = input:receive()
73 if error then 73 if error then
74 input:close() 74 input:close()
75 io.write("Removing client from set\n") 75 io.write("Removing client from set\n")
76 set:remove(input) 76 set:remove(input)
77 else 77 else
78 io.write("Broadcasting line '", line, "'\n") 78 io.write("Broadcasting line '", line, "'\n")
79 writable, error = socket.skip(1, socket.select(nil, set, 1)) 79 writable, error = socket.skip(1, socket.select(nil, set, 1))
80 if not error then 80 if not error then
81 for __, output in ipairs(writable) do 81 for __, output in ipairs(writable) do
82 if output ~= input then 82 if output ~= input then
83 output:send(line .. "\n") 83 output:send(line .. "\n")
84 end 84 end
85 end 85 end
diff --git a/src/ftp.lua b/src/ftp.lua
index c83c1cb..5e1b685 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -40,7 +40,7 @@ function open(server, port, create)
40 local f = base.setmetatable({ tp = tp }, metat) 40 local f = base.setmetatable({ tp = tp }, metat)
41 -- make sure everything gets closed in an exception 41 -- make sure everything gets closed in an exception
42 f.try = socket.newtry(function() f:close() end) 42 f.try = socket.newtry(function() f:close() end)
43 return f 43 return f
44end 44end
45 45
46function metat.__index:portconnect() 46function metat.__index:portconnect()
@@ -71,20 +71,20 @@ function metat.__index:pasv()
71 local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" 71 local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
72 local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) 72 local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
73 self.try(a and b and c and d and p1 and p2, reply) 73 self.try(a and b and c and d and p1 and p2, reply)
74 self.pasvt = { 74 self.pasvt = {
75 ip = string.format("%d.%d.%d.%d", a, b, c, d), 75 ip = string.format("%d.%d.%d.%d", a, b, c, d),
76 port = p1*256 + p2 76 port = p1*256 + p2
77 } 77 }
78 if self.server then 78 if self.server then
79 self.server:close() 79 self.server:close()
80 self.server = nil 80 self.server = nil
81 end 81 end
82 return self.pasvt.ip, self.pasvt.port 82 return self.pasvt.ip, self.pasvt.port
83end 83end
84 84
85function metat.__index:port(ip, port) 85function metat.__index:port(ip, port)
86 self.pasvt = nil 86 self.pasvt = nil
87 if not ip then 87 if not ip then
88 ip, port = self.try(self.tp:getcontrol():getsockname()) 88 ip, port = self.try(self.tp:getcontrol():getsockname())
89 self.server = self.try(socket.bind(ip, 0)) 89 self.server = self.try(socket.bind(ip, 0))
90 ip, port = self.try(self.server:getsockname()) 90 ip, port = self.try(self.server:getsockname())
@@ -100,11 +100,11 @@ end
100 100
101function metat.__index:send(sendt) 101function metat.__index:send(sendt)
102 self.try(self.pasvt or self.server, "need port or pasv first") 102 self.try(self.pasvt or self.server, "need port or pasv first")
103 -- if there is a pasvt table, we already sent a PASV command 103 -- if there is a pasvt table, we already sent a PASV command
104 -- we just get the data connection into self.data 104 -- we just get the data connection into self.data
105 if self.pasvt then self:pasvconnect() end 105 if self.pasvt then self:pasvconnect() end
106 -- get the transfer argument and command 106 -- get the transfer argument and command
107 local argument = sendt.argument or 107 local argument = sendt.argument or
108 url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) 108 url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
109 if argument == "" then argument = nil end 109 if argument == "" then argument = nil end
110 local command = sendt.command or "stor" 110 local command = sendt.command or "stor"
@@ -137,7 +137,7 @@ end
137function metat.__index:receive(recvt) 137function metat.__index:receive(recvt)
138 self.try(self.pasvt or self.server, "need port or pasv first") 138 self.try(self.pasvt or self.server, "need port or pasv first")
139 if self.pasvt then self:pasvconnect() end 139 if self.pasvt then self:pasvconnect() end
140 local argument = recvt.argument or 140 local argument = recvt.argument or
141 url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) 141 url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
142 if argument == "" then argument = nil end 142 if argument == "" then argument = nil end
143 local command = recvt.command or "retr" 143 local command = recvt.command or "retr"
@@ -220,7 +220,7 @@ local function parse(u)
220 socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") 220 socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
221 socket.try(t.host, "missing hostname") 221 socket.try(t.host, "missing hostname")
222 local pat = "^type=(.)$" 222 local pat = "^type=(.)$"
223 if t.params then 223 if t.params then
224 t.type = socket.skip(2, string.find(t.params, pat)) 224 t.type = socket.skip(2, string.find(t.params, pat))
225 socket.try(t.type == "a" or t.type == "i", 225 socket.try(t.type == "a" or t.type == "i",
226 "invalid type '" .. t.type .. "'") 226 "invalid type '" .. t.type .. "'")
@@ -229,7 +229,7 @@ local function parse(u)
229end 229end
230 230
231local function sput(u, body) 231local function sput(u, body)
232 local putt = parse(u) 232 local putt = parse(u)
233 putt.source = ltn12.source.string(body) 233 putt.source = ltn12.source.string(body)
234 return tput(putt) 234 return tput(putt)
235end 235end
@@ -253,7 +253,7 @@ local function tget(gett)
253end 253end
254 254
255local function sget(u) 255local function sget(u)
256 local gett = parse(u) 256 local gett = parse(u)
257 local t = {} 257 local t = {}
258 gett.sink = ltn12.sink.table(t) 258 gett.sink = ltn12.sink.table(t)
259 tget(gett) 259 tget(gett)
diff --git a/src/http.lua b/src/http.lua
index f08da07..1834061 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -21,7 +21,7 @@ module("socket.http")
21-- Program constants 21-- Program constants
22----------------------------------------------------------------------------- 22-----------------------------------------------------------------------------
23-- connection timeout in seconds 23-- connection timeout in seconds
24TIMEOUT = 60 24TIMEOUT = 60
25-- default port for document retrieval 25-- default port for document retrieval
26PORT = 80 26PORT = 80
27-- user agent field sent in request 27-- user agent field sent in request
@@ -65,18 +65,18 @@ socket.sourcet["http-chunked"] = function(sock, headers)
65 return base.setmetatable({ 65 return base.setmetatable({
66 getfd = function() return sock:getfd() end, 66 getfd = function() return sock:getfd() end,
67 dirty = function() return sock:dirty() end 67 dirty = function() return sock:dirty() end
68 }, { 68 }, {
69 __call = function() 69 __call = function()
70 -- get chunk size, skip extention 70 -- get chunk size, skip extention
71 local line, err = sock:receive() 71 local line, err = sock:receive()
72 if err then return nil, err end 72 if err then return nil, err end
73 local size = base.tonumber(string.gsub(line, ";.*", ""), 16) 73 local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
74 if not size then return nil, "invalid chunk size" end 74 if not size then return nil, "invalid chunk size" end
75 -- was it the last chunk? 75 -- was it the last chunk?
76 if size > 0 then 76 if size > 0 then
77 -- if not, get chunk and skip terminating CRLF 77 -- if not, get chunk and skip terminating CRLF
78 local chunk, err, part = sock:receive(size) 78 local chunk, err, part = sock:receive(size)
79 if chunk then sock:receive() end 79 if chunk then sock:receive() end
80 return chunk, err 80 return chunk, err
81 else 81 else
82 -- if it was, read trailers into headers table 82 -- if it was, read trailers into headers table
@@ -91,7 +91,7 @@ socket.sinkt["http-chunked"] = function(sock)
91 return base.setmetatable({ 91 return base.setmetatable({
92 getfd = function() return sock:getfd() end, 92 getfd = function() return sock:getfd() end,
93 dirty = function() return sock:dirty() end 93 dirty = function() return sock:dirty() end
94 }, { 94 }, {
95 __call = function(self, chunk, err) 95 __call = function(self, chunk, err)
96 if not chunk then return sock:send("0\r\n\r\n") end 96 if not chunk then return sock:send("0\r\n\r\n") end
97 local size = string.format("%X\r\n", string.len(chunk)) 97 local size = string.format("%X\r\n", string.len(chunk))
@@ -115,11 +115,11 @@ function open(host, port, create)
115 h.try(c:settimeout(TIMEOUT)) 115 h.try(c:settimeout(TIMEOUT))
116 h.try(c:connect(host, port or PORT)) 116 h.try(c:connect(host, port or PORT))
117 -- here everything worked 117 -- here everything worked
118 return h 118 return h
119end 119end
120 120
121function metat.__index:sendrequestline(method, uri) 121function metat.__index:sendrequestline(method, uri)
122 local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) 122 local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
123 return self.try(self.c:send(reqline)) 123 return self.try(self.c:send(reqline))
124end 124end
125 125
@@ -133,7 +133,7 @@ function metat.__index:sendheaders(headers)
133end 133end
134 134
135function metat.__index:sendbody(headers, source, step) 135function metat.__index:sendbody(headers, source, step)
136 source = source or ltn12.source.empty() 136 source = source or ltn12.source.empty()
137 step = step or ltn12.pump.step 137 step = step or ltn12.pump.step
138 -- if we don't know the size in advance, send chunked and hope for the best 138 -- if we don't know the size in advance, send chunked and hope for the best
139 local mode = "http-chunked" 139 local mode = "http-chunked"
@@ -159,7 +159,7 @@ function metat.__index:receivebody(headers, sink, step)
159 local mode = "default" -- connection close 159 local mode = "default" -- connection close
160 if t and t ~= "identity" then mode = "http-chunked" 160 if t and t ~= "identity" then mode = "http-chunked"
161 elseif base.tonumber(headers["content-length"]) then mode = "by-length" end 161 elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
162 return self.try(ltn12.pump.all(socket.source(mode, self.c, length), 162 return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
163 sink, step)) 163 sink, step))
164end 164end
165 165
@@ -185,7 +185,7 @@ local function adjusturi(reqt)
185end 185end
186 186
187local function adjustproxy(reqt) 187local function adjustproxy(reqt)
188 local proxy = reqt.proxy or PROXY 188 local proxy = reqt.proxy or PROXY
189 if proxy then 189 if proxy then
190 proxy = url.parse(proxy) 190 proxy = url.parse(proxy)
191 return proxy.host, proxy.port or 3128 191 return proxy.host, proxy.port or 3128
@@ -292,10 +292,10 @@ function trequest(reqt)
292 local code, headers, status 292 local code, headers, status
293 code, status = h:receivestatusline() 293 code, status = h:receivestatusline()
294 headers = h:receiveheaders() 294 headers = h:receiveheaders()
295 if shouldredirect(reqt, code, headers) then 295 if shouldredirect(reqt, code, headers) then
296 h:close() 296 h:close()
297 return tredirect(reqt, headers.location) 297 return tredirect(reqt, headers.location)
298 elseif shouldauthorize(reqt, code) then 298 elseif shouldauthorize(reqt, code) then
299 h:close() 299 h:close()
300 return tauthorize(reqt) 300 return tauthorize(reqt)
301 elseif shouldreceivebody(reqt, code) then 301 elseif shouldreceivebody(reqt, code) then
@@ -307,12 +307,12 @@ end
307 307
308local function srequest(u, body) 308local function srequest(u, body)
309 local t = {} 309 local t = {}
310 local reqt = { 310 local reqt = {
311 url = u, 311 url = u,
312 sink = ltn12.sink.table(t) 312 sink = ltn12.sink.table(t)
313 } 313 }
314 if body then 314 if body then
315 reqt.source = ltn12.source.string(body) 315 reqt.source = ltn12.source.string(body)
316 reqt.headers = { ["content-length"] = string.len(body) } 316 reqt.headers = { ["content-length"] = string.len(body) }
317 reqt.method = "POST" 317 reqt.method = "POST"
318 end 318 end
diff --git a/src/ltn12.lua b/src/ltn12.lua
index 2c16253..c49d130 100644
--- a/src/ltn12.lua
+++ b/src/ltn12.lua
@@ -36,19 +36,19 @@ end
36 36
37-- chains a bunch of filters together 37-- chains a bunch of filters together
38-- (thanks to Wim Couwenberg) 38-- (thanks to Wim Couwenberg)
39function filter.chain(...) 39function filter.chain(...)
40 local n = table.getn(arg) 40 local n = table.getn(arg)
41 local top, index = 1, 1 41 local top, index = 1, 1
42 local retry = "" 42 local retry = ""
43 return function(chunk) 43 return function(chunk)
44 retry = chunk and retry 44 retry = chunk and retry
45 while true do 45 while true do
46 if index == top then 46 if index == top then
47 chunk = arg[index](chunk) 47 chunk = arg[index](chunk)
48 if chunk == "" or top == n then return chunk 48 if chunk == "" or top == n then return chunk
49 elseif chunk then index = index + 1 49 elseif chunk then index = index + 1
50 else 50 else
51 top = top+1 51 top = top+1
52 index = top 52 index = top
53 end 53 end
54 else 54 else
@@ -148,9 +148,9 @@ function source.chain(src, f)
148 last_in, err = src() 148 last_in, err = src()
149 if err then return nil, err end 149 if err then return nil, err end
150 last_out = f(last_in) 150 last_out = f(last_in)
151 if not last_out then 151 if not last_out then
152 if last_in then 152 if last_in then
153 base.error('filter returned inappropriate nil') 153 base.error('filter returned inappropriate nil')
154 else 154 else
155 return nil 155 return nil
156 end 156 end
@@ -159,17 +159,17 @@ function source.chain(src, f)
159 if last_in then last_in = "" end 159 if last_in then last_in = "" end
160 return last_out 160 return last_out
161 end 161 end
162 else 162 else
163 last_out = f(last_in) 163 last_out = f(last_in)
164 if last_out == "" then 164 if last_out == "" then
165 if last_in == "" then 165 if last_in == "" then
166 state = "feeding" 166 state = "feeding"
167 else 167 else
168 base.error('filter returned ""') 168 base.error('filter returned ""')
169 end 169 end
170 elseif not last_out then 170 elseif not last_out then
171 if last_in then 171 if last_in then
172 base.error('filter returned inappropriate nil') 172 base.error('filter returned inappropriate nil')
173 else 173 else
174 return nil 174 return nil
175 end 175 end
@@ -224,7 +224,7 @@ end
224function sink.file(handle, io_err) 224function sink.file(handle, io_err)
225 if handle then 225 if handle then
226 return function(chunk, err) 226 return function(chunk, err)
227 if not chunk then 227 if not chunk then
228 handle:close() 228 handle:close()
229 return 1 229 return 1
230 else return handle:write(chunk) end 230 else return handle:write(chunk) end
@@ -248,7 +248,7 @@ function sink.error(err)
248 end 248 end
249end 249end
250 250
251-- chains a sink with a filter 251-- chains a sink with a filter
252function sink.chain(f, snk) 252function sink.chain(f, snk)
253 base.assert(f and snk) 253 base.assert(f and snk)
254 return function(chunk, err) 254 return function(chunk, err)
@@ -282,7 +282,7 @@ function pump.all(src, snk, step)
282 step = step or pump.step 282 step = step or pump.step
283 while true do 283 while true do
284 local ret, err = step(src, snk) 284 local ret, err = step(src, snk)
285 if not ret then 285 if not ret then
286 if err then return nil, err 286 if err then return nil, err
287 else return 1 end 287 else return 1 end
288 end 288 end
diff --git a/src/mbox.lua b/src/mbox.lua
index f52719b..ce6537c 100644
--- a/src/mbox.lua
+++ b/src/mbox.lua
@@ -10,7 +10,7 @@ function Public.split_message(message_s)
10 if not message.body then 10 if not message.body then
11 string.gsub(message_s, "^\n(.*)", function (b) message.body = b end) 11 string.gsub(message_s, "^\n(.*)", function (b) message.body = b end)
12 end 12 end
13 if not message.headers and not message.body then 13 if not message.headers and not message.body then
14 message.headers = message_s 14 message.headers = message_s
15 end 15 end
16 return message.headers or "", message.body or "" 16 return message.headers or "", message.body or ""
diff --git a/src/mime.lua b/src/mime.lua
index f6a9333..3182545 100644
--- a/src/mime.lua
+++ b/src/mime.lua
@@ -20,10 +20,10 @@ encodet = {}
20decodet = {} 20decodet = {}
21wrapt = {} 21wrapt = {}
22 22
23-- creates a function that chooses a filter by name from a given table 23-- creates a function that chooses a filter by name from a given table
24local function choose(table) 24local function choose(table)
25 return function(name, opt1, opt2) 25 return function(name, opt1, opt2)
26 if base.type(name) ~= "string" then 26 if base.type(name) ~= "string" then
27 name, opt1, opt2 = "default", name, opt1 27 name, opt1, opt2 = "default", name, opt1
28 end 28 end
29 local f = table[name or "nil"] 29 local f = table[name or "nil"]
@@ -38,7 +38,7 @@ encodet['base64'] = function()
38end 38end
39 39
40encodet['quoted-printable'] = function(mode) 40encodet['quoted-printable'] = function(mode)
41 return ltn12.filter.cycle(qp, "", 41 return ltn12.filter.cycle(qp, "",
42 (mode == "binary") and "=0D=0A" or "\r\n") 42 (mode == "binary") and "=0D=0A" or "\r\n")
43end 43end
44 44
@@ -56,22 +56,22 @@ local function format(chunk)
56 if chunk == "" then return "''" 56 if chunk == "" then return "''"
57 else return string.len(chunk) end 57 else return string.len(chunk) end
58 else return "nil" end 58 else return "nil" end
59end 59end
60 60
61-- define the line-wrap filters 61-- define the line-wrap filters
62wrapt['text'] = function(length) 62wrapt['text'] = function(length)
63 length = length or 76 63 length = length or 76
64 return ltn12.filter.cycle(wrp, length, length) 64 return ltn12.filter.cycle(wrp, length, length)
65end 65end
66wrapt['base64'] = wrapt['text'] 66wrapt['base64'] = wrapt['text']
67wrapt['default'] = wrapt['text'] 67wrapt['default'] = wrapt['text']
68 68
69wrapt['quoted-printable'] = function() 69wrapt['quoted-printable'] = function()
70 return ltn12.filter.cycle(qpwrp, 76, 76) 70 return ltn12.filter.cycle(qpwrp, 76, 76)
71end 71end
72 72
73-- function that choose the encoding, decoding or wrap algorithm 73-- function that choose the encoding, decoding or wrap algorithm
74encode = choose(encodet) 74encode = choose(encodet)
75decode = choose(decodet) 75decode = choose(decodet)
76wrap = choose(wrapt) 76wrap = choose(wrapt)
77 77
diff --git a/src/smtp.lua b/src/smtp.lua
index 03b9e9b..72c4234 100644
--- a/src/smtp.lua
+++ b/src/smtp.lua
@@ -27,8 +27,8 @@ TIMEOUT = 60
27-- default server used to send e-mails 27-- default server used to send e-mails
28SERVER = "localhost" 28SERVER = "localhost"
29-- default port 29-- default port
30PORT = 25 30PORT = 25
31-- domain used in HELO command and default sendmail 31-- domain used in HELO command and default sendmail
32-- If we are under a CGI, try to get from environment 32-- If we are under a CGI, try to get from environment
33DOMAIN = os.getenv("SERVER_NAME") or "localhost" 33DOMAIN = os.getenv("SERVER_NAME") or "localhost"
34-- default time zone (means we don't know) 34-- default time zone (means we don't know)
@@ -43,12 +43,12 @@ function metat.__index:greet(domain)
43 self.try(self.tp:check("2..")) 43 self.try(self.tp:check("2.."))
44 self.try(self.tp:command("EHLO", domain or DOMAIN)) 44 self.try(self.tp:command("EHLO", domain or DOMAIN))
45 return socket.skip(1, self.try(self.tp:check("2.."))) 45 return socket.skip(1, self.try(self.tp:check("2..")))
46end 46end
47 47
48function metat.__index:mail(from) 48function metat.__index:mail(from)
49 self.try(self.tp:command("MAIL", "FROM:" .. from)) 49 self.try(self.tp:command("MAIL", "FROM:" .. from))
50 return self.try(self.tp:check("2..")) 50 return self.try(self.tp:check("2.."))
51end 51end
52 52
53function metat.__index:rcpt(to) 53function metat.__index:rcpt(to)
54 self.try(self.tp:command("RCPT", "TO:" .. to)) 54 self.try(self.tp:command("RCPT", "TO:" .. to))
@@ -99,7 +99,7 @@ function metat.__index:auth(user, password, ext)
99end 99end
100 100
101-- send message or throw an exception 101-- send message or throw an exception
102function metat.__index:send(mailt) 102function metat.__index:send(mailt)
103 self:mail(mailt.from) 103 self:mail(mailt.from)
104 if base.type(mailt.rcpt) == "table" then 104 if base.type(mailt.rcpt) == "table" then
105 for i,v in base.ipairs(mailt.rcpt) do 105 for i,v in base.ipairs(mailt.rcpt) do
@@ -112,14 +112,14 @@ function metat.__index:send(mailt)
112end 112end
113 113
114function open(server, port, create) 114function open(server, port, create)
115 local tp = socket.try(tp.connect(server or SERVER, port or PORT, 115 local tp = socket.try(tp.connect(server or SERVER, port or PORT,
116 create, TIMEOUT)) 116 create, TIMEOUT))
117 local s = base.setmetatable({tp = tp}, metat) 117 local s = base.setmetatable({tp = tp}, metat)
118 -- make sure tp is closed if we get an exception 118 -- make sure tp is closed if we get an exception
119 s.try = socket.newtry(function() 119 s.try = socket.newtry(function()
120 s:close() 120 s:close()
121 end) 121 end)
122 return s 122 return s
123end 123end
124 124
125--------------------------------------------------------------------------- 125---------------------------------------------------------------------------
@@ -142,7 +142,7 @@ local function send_headers(headers)
142 for i,v in base.pairs(headers) do 142 for i,v in base.pairs(headers) do
143 h = i .. ': ' .. v .. "\r\n" .. h 143 h = i .. ': ' .. v .. "\r\n" .. h
144 end 144 end
145 coroutine.yield(h) 145 coroutine.yield(h)
146end 146end
147 147
148-- yield multipart message body from a multipart message table 148-- yield multipart message body from a multipart message table
@@ -151,25 +151,25 @@ local function send_multipart(mesgt)
151 local bd = newboundary() 151 local bd = newboundary()
152 local headers = mesgt.headers or {} 152 local headers = mesgt.headers or {}
153 headers['content-type'] = headers['content-type'] or 'multipart/mixed' 153 headers['content-type'] = headers['content-type'] or 'multipart/mixed'
154 headers['content-type'] = headers['content-type'] .. 154 headers['content-type'] = headers['content-type'] ..
155 '; boundary="' .. bd .. '"' 155 '; boundary="' .. bd .. '"'
156 send_headers(headers) 156 send_headers(headers)
157 -- send preamble 157 -- send preamble
158 if mesgt.body.preamble then 158 if mesgt.body.preamble then
159 coroutine.yield(mesgt.body.preamble) 159 coroutine.yield(mesgt.body.preamble)
160 coroutine.yield("\r\n") 160 coroutine.yield("\r\n")
161 end 161 end
162 -- send each part separated by a boundary 162 -- send each part separated by a boundary
163 for i, m in base.ipairs(mesgt.body) do 163 for i, m in base.ipairs(mesgt.body) do
164 coroutine.yield("\r\n--" .. bd .. "\r\n") 164 coroutine.yield("\r\n--" .. bd .. "\r\n")
165 send_message(m) 165 send_message(m)
166 end 166 end
167 -- send last boundary 167 -- send last boundary
168 coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") 168 coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
169 -- send epilogue 169 -- send epilogue
170 if mesgt.body.epilogue then 170 if mesgt.body.epilogue then
171 coroutine.yield(mesgt.body.epilogue) 171 coroutine.yield(mesgt.body.epilogue)
172 coroutine.yield("\r\n") 172 coroutine.yield("\r\n")
173 end 173 end
174end 174end
175 175
@@ -181,7 +181,7 @@ local function send_source(mesgt)
181 'text/plain; charset="iso-8859-1"' 181 'text/plain; charset="iso-8859-1"'
182 send_headers(headers) 182 send_headers(headers)
183 -- send body from source 183 -- send body from source
184 while true do 184 while true do
185 local chunk, err = mesgt.body() 185 local chunk, err = mesgt.body()
186 if err then coroutine.yield(nil, err) 186 if err then coroutine.yield(nil, err)
187 elseif chunk then coroutine.yield(chunk) 187 elseif chunk then coroutine.yield(chunk)
@@ -213,11 +213,11 @@ local function adjust_headers(mesgt)
213 for i,v in base.pairs(mesgt.headers or lower) do 213 for i,v in base.pairs(mesgt.headers or lower) do
214 lower[string.lower(i)] = v 214 lower[string.lower(i)] = v
215 end 215 end
216 lower["date"] = lower["date"] or 216 lower["date"] = lower["date"] or
217 os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE) 217 os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
218 lower["x-mailer"] = lower["x-mailer"] or socket._VERSION 218 lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
219 -- this can't be overriden 219 -- this can't be overriden
220 lower["mime-version"] = "1.0" 220 lower["mime-version"] = "1.0"
221 mesgt.headers = lower 221 mesgt.headers = lower
222end 222end
223 223
@@ -225,7 +225,7 @@ function message(mesgt)
225 adjust_headers(mesgt) 225 adjust_headers(mesgt)
226 -- create and return message source 226 -- create and return message source
227 local co = coroutine.create(function() send_message(mesgt) end) 227 local co = coroutine.create(function() send_message(mesgt) end)
228 return function() 228 return function()
229 local ret, a, b = coroutine.resume(co) 229 local ret, a, b = coroutine.resume(co)
230 if ret then return a, b 230 if ret then return a, b
231 else return nil, a end 231 else return nil, a end
diff --git a/src/socket.lua b/src/socket.lua
index 6eb3159..458418e 100644
--- a/src/socket.lua
+++ b/src/socket.lua
@@ -19,7 +19,7 @@ module("socket")
19function connect(address, port, laddress, lport) 19function connect(address, port, laddress, lport)
20 local sock, err = socket.tcp() 20 local sock, err = socket.tcp()
21 if not sock then return nil, err end 21 if not sock then return nil, err end
22 if laddress then 22 if laddress then
23 local res, err = sock:bind(laddress, lport, -1) 23 local res, err = sock:bind(laddress, lport, -1)
24 if not res then return nil, err end 24 if not res then return nil, err end
25 end 25 end
@@ -65,9 +65,9 @@ sinkt["close-when-done"] = function(sock)
65 return base.setmetatable({ 65 return base.setmetatable({
66 getfd = function() return sock:getfd() end, 66 getfd = function() return sock:getfd() end,
67 dirty = function() return sock:dirty() end 67 dirty = function() return sock:dirty() end
68 }, { 68 }, {
69 __call = function(self, chunk, err) 69 __call = function(self, chunk, err)
70 if not chunk then 70 if not chunk then
71 sock:close() 71 sock:close()
72 return 1 72 return 1
73 else return sock:send(chunk) end 73 else return sock:send(chunk) end
@@ -79,7 +79,7 @@ sinkt["keep-open"] = function(sock)
79 return base.setmetatable({ 79 return base.setmetatable({
80 getfd = function() return sock:getfd() end, 80 getfd = function() return sock:getfd() end,
81 dirty = function() return sock:dirty() end 81 dirty = function() return sock:dirty() end
82 }, { 82 }, {
83 __call = function(self, chunk, err) 83 __call = function(self, chunk, err)
84 if chunk then return sock:send(chunk) 84 if chunk then return sock:send(chunk)
85 else return 1 end 85 else return 1 end
@@ -95,7 +95,7 @@ sourcet["by-length"] = function(sock, length)
95 return base.setmetatable({ 95 return base.setmetatable({
96 getfd = function() return sock:getfd() end, 96 getfd = function() return sock:getfd() end,
97 dirty = function() return sock:dirty() end 97 dirty = function() return sock:dirty() end
98 }, { 98 }, {
99 __call = function() 99 __call = function()
100 if length <= 0 then return nil end 100 if length <= 0 then return nil end
101 local size = math.min(socket.BLOCKSIZE, length) 101 local size = math.min(socket.BLOCKSIZE, length)
@@ -112,16 +112,16 @@ sourcet["until-closed"] = function(sock)
112 return base.setmetatable({ 112 return base.setmetatable({
113 getfd = function() return sock:getfd() end, 113 getfd = function() return sock:getfd() end,
114 dirty = function() return sock:dirty() end 114 dirty = function() return sock:dirty() end
115 }, { 115 }, {
116 __call = function() 116 __call = function()
117 if done then return nil end 117 if done then return nil end
118 local chunk, err, partial = sock:receive(socket.BLOCKSIZE) 118 local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
119 if not err then return chunk 119 if not err then return chunk
120 elseif err == "closed" then 120 elseif err == "closed" then
121 sock:close() 121 sock:close()
122 done = 1 122 done = 1
123 return partial 123 return partial
124 else return nil, err end 124 else return nil, err end
125 end 125 end
126 }) 126 })
127end 127end
diff --git a/src/tp.lua b/src/tp.lua
index 984bd67..c6d60c8 100644
--- a/src/tp.lua
+++ b/src/tp.lua
@@ -37,7 +37,7 @@ local function get_reply(c)
37 current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) 37 current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
38 reply = reply .. "\n" .. line 38 reply = reply .. "\n" .. line
39 -- reply ends with same code 39 -- reply ends with same code
40 until code == current and sep == " " 40 until code == current and sep == " "
41 end 41 end
42 return code, reply 42 return code, reply
43end 43end
@@ -49,25 +49,25 @@ function metat.__index:check(ok)
49 local code, reply = get_reply(self.c) 49 local code, reply = get_reply(self.c)
50 if not code then return nil, reply end 50 if not code then return nil, reply end
51 if base.type(ok) ~= "function" then 51 if base.type(ok) ~= "function" then
52 if base.type(ok) == "table" then 52 if base.type(ok) == "table" then
53 for i, v in base.ipairs(ok) do 53 for i, v in base.ipairs(ok) do
54 if string.find(code, v) then 54 if string.find(code, v) then
55 return base.tonumber(code), reply 55 return base.tonumber(code), reply
56 end 56 end
57 end 57 end
58 return nil, reply 58 return nil, reply
59 else 59 else
60 if string.find(code, ok) then return base.tonumber(code), reply 60 if string.find(code, ok) then return base.tonumber(code), reply
61 else return nil, reply end 61 else return nil, reply end
62 end 62 end
63 else return ok(base.tonumber(code), reply) end 63 else return ok(base.tonumber(code), reply) end
64end 64end
65 65
66function metat.__index:command(cmd, arg) 66function metat.__index:command(cmd, arg)
67 if arg then 67 if arg then
68 return self.c:send(cmd .. " " .. arg.. "\r\n") 68 return self.c:send(cmd .. " " .. arg.. "\r\n")
69 else 69 else
70 return self.c:send(cmd .. "\r\n") 70 return self.c:send(cmd .. "\r\n")
71 end 71 end
72end 72end
73 73
@@ -114,8 +114,8 @@ function connect(host, port, create, timeout)
114 if not c then return nil, e end 114 if not c then return nil, e end
115 c:settimeout(timeout or TIMEOUT) 115 c:settimeout(timeout or TIMEOUT)
116 local r, e = c:connect(host, port) 116 local r, e = c:connect(host, port)
117 if not r then 117 if not r then
118 c:close() 118 c:close()
119 return nil, e 119 return nil, e
120 end 120 end
121 return base.setmetatable({c = c}, metat) 121 return base.setmetatable({c = c}, metat)
diff --git a/src/url.lua b/src/url.lua
index 135d723..c700f90 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -20,7 +20,7 @@ _VERSION = "URL 1.0"
20 20
21----------------------------------------------------------------------------- 21-----------------------------------------------------------------------------
22-- Encodes a string into its escaped hexadecimal representation 22-- Encodes a string into its escaped hexadecimal representation
23-- Input 23-- Input
24-- s: binary string to be encoded 24-- s: binary string to be encoded
25-- Returns 25-- Returns
26-- escaped representation of string binary 26-- escaped representation of string binary
@@ -33,8 +33,8 @@ end
33 33
34----------------------------------------------------------------------------- 34-----------------------------------------------------------------------------
35-- Protects a path segment, to prevent it from interfering with the 35-- Protects a path segment, to prevent it from interfering with the
36-- url parsing. 36-- url parsing.
37-- Input 37-- Input
38-- s: binary string to be encoded 38-- s: binary string to be encoded
39-- Returns 39-- Returns
40-- escaped representation of string binary 40-- escaped representation of string binary
@@ -50,12 +50,12 @@ end
50-- these are allowed withing a path segment, along with alphanum 50-- these are allowed withing a path segment, along with alphanum
51-- other characters must be escaped 51-- other characters must be escaped
52local segment_set = make_set { 52local segment_set = make_set {
53 "-", "_", ".", "!", "~", "*", "'", "(", 53 "-", "_", ".", "!", "~", "*", "'", "(",
54 ")", ":", "@", "&", "=", "+", "$", ",", 54 ")", ":", "@", "&", "=", "+", "$", ",",
55} 55}
56 56
57local function protect_segment(s) 57local function protect_segment(s)
58 return string.gsub(s, "([^A-Za-z0-9_])", function (c) 58 return string.gsub(s, "([^A-Za-z0-9_])", function (c)
59 if segment_set[c] then return c 59 if segment_set[c] then return c
60 else return string.format("%%%02x", string.byte(c)) end 60 else return string.format("%%%02x", string.byte(c)) end
61 end) 61 end)
@@ -63,7 +63,7 @@ end
63 63
64----------------------------------------------------------------------------- 64-----------------------------------------------------------------------------
65-- Encodes a string into its escaped hexadecimal representation 65-- Encodes a string into its escaped hexadecimal representation
66-- Input 66-- Input
67-- s: binary string to be encoded 67-- s: binary string to be encoded
68-- Returns 68-- Returns
69-- escaped representation of string binary 69-- escaped representation of string binary
@@ -86,11 +86,11 @@ local function absolute_path(base_path, relative_path)
86 if string.sub(relative_path, 1, 1) == "/" then return relative_path end 86 if string.sub(relative_path, 1, 1) == "/" then return relative_path end
87 local path = string.gsub(base_path, "[^/]*$", "") 87 local path = string.gsub(base_path, "[^/]*$", "")
88 path = path .. relative_path 88 path = path .. relative_path
89 path = string.gsub(path, "([^/]*%./)", function (s) 89 path = string.gsub(path, "([^/]*%./)", function (s)
90 if s ~= "./" then return s else return "" end 90 if s ~= "./" then return s else return "" end
91 end) 91 end)
92 path = string.gsub(path, "/%.$", "/") 92 path = string.gsub(path, "/%.$", "/")
93 local reduced 93 local reduced
94 while reduced ~= path do 94 while reduced ~= path do
95 reduced = path 95 reduced = path
96 path = string.gsub(reduced, "([^/]*/%.%./)", function (s) 96 path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
@@ -116,7 +116,7 @@ end
116-- Returns 116-- Returns
117-- table with the following fields, where RFC naming conventions have 117-- table with the following fields, where RFC naming conventions have
118-- been preserved: 118-- been preserved:
119-- scheme, authority, userinfo, user, password, host, port, 119-- scheme, authority, userinfo, user, password, host, port,
120-- path, params, query, fragment 120-- path, params, query, fragment
121-- Obs: 121-- Obs:
122-- the leading '/' in {/<path>} is considered part of <path> 122-- the leading '/' in {/<path>} is considered part of <path>
@@ -130,26 +130,26 @@ function parse(url, default)
130 -- remove whitespace 130 -- remove whitespace
131 -- url = string.gsub(url, "%s", "") 131 -- url = string.gsub(url, "%s", "")
132 -- get fragment 132 -- get fragment
133 url = string.gsub(url, "#(.*)$", function(f) 133 url = string.gsub(url, "#(.*)$", function(f)
134 parsed.fragment = f 134 parsed.fragment = f
135 return "" 135 return ""
136 end) 136 end)
137 -- get scheme 137 -- get scheme
138 url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", 138 url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
139 function(s) parsed.scheme = s; return "" end) 139 function(s) parsed.scheme = s; return "" end)
140 -- get authority 140 -- get authority
141 url = string.gsub(url, "^//([^/]*)", function(n) 141 url = string.gsub(url, "^//([^/]*)", function(n)
142 parsed.authority = n 142 parsed.authority = n
143 return "" 143 return ""
144 end) 144 end)
145 -- get query stringing 145 -- get query stringing
146 url = string.gsub(url, "%?(.*)", function(q) 146 url = string.gsub(url, "%?(.*)", function(q)
147 parsed.query = q 147 parsed.query = q
148 return "" 148 return ""
149 end) 149 end)
150 -- get params 150 -- get params
151 url = string.gsub(url, "%;(.*)", function(p) 151 url = string.gsub(url, "%;(.*)", function(p)
152 parsed.params = p 152 parsed.params = p
153 return "" 153 return ""
154 end) 154 end)
155 -- path is whatever was left 155 -- path is whatever was left
@@ -158,14 +158,14 @@ function parse(url, default)
158 if not authority then return parsed end 158 if not authority then return parsed end
159 authority = string.gsub(authority,"^([^@]*)@", 159 authority = string.gsub(authority,"^([^@]*)@",
160 function(u) parsed.userinfo = u; return "" end) 160 function(u) parsed.userinfo = u; return "" end)
161 authority = string.gsub(authority, ":([^:]*)$", 161 authority = string.gsub(authority, ":([^:]*)$",
162 function(p) parsed.port = p; return "" end) 162 function(p) parsed.port = p; return "" end)
163 if authority ~= "" then parsed.host = authority end 163 if authority ~= "" then parsed.host = authority end
164 local userinfo = parsed.userinfo 164 local userinfo = parsed.userinfo
165 if not userinfo then return parsed end 165 if not userinfo then return parsed end
166 userinfo = string.gsub(userinfo, ":([^:]*)$", 166 userinfo = string.gsub(userinfo, ":([^:]*)$",
167 function(p) parsed.password = p; return "" end) 167 function(p) parsed.password = p; return "" end)
168 parsed.user = userinfo 168 parsed.user = userinfo
169 return parsed 169 return parsed
170end 170end
171 171
@@ -189,8 +189,8 @@ function build(parsed)
189 local userinfo = parsed.userinfo 189 local userinfo = parsed.userinfo
190 if parsed.user then 190 if parsed.user then
191 userinfo = parsed.user 191 userinfo = parsed.user
192 if parsed.password then 192 if parsed.password then
193 userinfo = userinfo .. ":" .. parsed.password 193 userinfo = userinfo .. ":" .. parsed.password
194 end 194 end
195 end 195 end
196 if userinfo then authority = userinfo .. "@" .. authority end 196 if userinfo then authority = userinfo .. "@" .. authority end
@@ -233,8 +233,8 @@ function absolute(base_url, relative_url)
233 relative_parsed.query = base_parsed.query 233 relative_parsed.query = base_parsed.query
234 end 234 end
235 end 235 end
236 else 236 else
237 relative_parsed.path = absolute_path(base_parsed.path or "", 237 relative_parsed.path = absolute_path(base_parsed.path or "",
238 relative_parsed.path) 238 relative_parsed.path)
239 end 239 end
240 end 240 end
diff --git a/src/usocket.c b/src/usocket.c
index 6a0b178..e70806a 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -110,7 +110,8 @@ int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
110 double t = timeout_getretry(tm); 110 double t = timeout_getretry(tm);
111 tv.tv_sec = (int) t; 111 tv.tv_sec = (int) t;
112 tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); 112 tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
113 ret = select(n, rfds, wfds, efds, t >= 0.0? &tv: NULL); 113 /* timeout = 0 means no wait */
114 ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL);
114 } while (ret < 0 && errno == EINTR); 115 } while (ret < 0 && errno == EINTR);
115 return ret; 116 return ret;
116} 117}