aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2011-05-25 20:57:22 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2011-05-25 20:57:22 +0000
commit3a8ba90dfb0c2eb224f317dd692ede426691e72a (patch)
treefe1cc5379a2e0e031663fe9c15d908653844bc73
parentbce60be30fe8e9c1b0eb33128c23c93d7bca5303 (diff)
downloadluasocket-3a8ba90dfb0c2eb224f317dd692ede426691e72a.tar.gz
luasocket-3a8ba90dfb0c2eb224f317dd692ede426691e72a.tar.bz2
luasocket-3a8ba90dfb0c2eb224f317dd692ede426691e72a.zip
Saving before big changes to support IPv6.
-rw-r--r--FIX11
-rw-r--r--NEW46
-rw-r--r--doc/ftp.html6
-rw-r--r--doc/http.html13
-rw-r--r--doc/index.html16
-rw-r--r--doc/mime.html10
-rw-r--r--doc/smtp.html13
-rw-r--r--doc/url.html5
-rw-r--r--etc/dict.lua44
-rw-r--r--etc/get.lua106
-rw-r--r--etc/lp.lua8
-rw-r--r--etc/tftp.lua68
-rw-r--r--makefile16
-rw-r--r--src/buffer.c14
-rw-r--r--src/buffer.h4
-rw-r--r--src/ftp.lua4
-rw-r--r--src/inet.c3
-rw-r--r--src/makefile173
-rw-r--r--src/mbox.lua40
-rw-r--r--src/tp.lua2
-rw-r--r--src/url.lua122
-rw-r--r--src/usocket.c6
-rw-r--r--src/wsocket.c8
-rw-r--r--test/ftptest.lua8
-rw-r--r--test/httptest.lua188
-rw-r--r--test/smtptest.lua104
-rw-r--r--test/testclnt.lua122
-rw-r--r--test/testsupport.lua14
-rw-r--r--test/urltest.lua620
-rw-r--r--test/utestclnt.lua2
30 files changed, 947 insertions, 849 deletions
diff --git a/FIX b/FIX
index a688ba0..40f30a1 100644
--- a/FIX
+++ b/FIX
@@ -1,15 +1,14 @@
1http was preserving old host header during redirects
2fix smtp.send hang on source error
3add create field to FTP and SMTP and fix HTTP ugliness
4clean timeout argument to open functions in SMTP, HTTP and FTP
5eliminate globals from namespaces created by module().
6
7 1
8 2
9 3
10 4
11 5
12 6
7http was preserving old host header during redirects
8fix smtp.send hang on source error
9add create field to FTP and SMTP and fix HTTP ugliness
10clean timeout argument to open functions in SMTP, HTTP and FTP
11eliminate globals from namespaces created by module().
13url.absolute was not working when base_url was already parsed 12url.absolute was not working when base_url was already parsed
14http.request was redirecting even when the location header was empty 13http.request was redirecting even when the location header was empty
15tcp{client}:shutdown() was checking for group instead of class. 14tcp{client}:shutdown() was checking for group instead of class.
diff --git a/NEW b/NEW
index 6c6b095..76b8448 100644
--- a/NEW
+++ b/NEW
@@ -2,19 +2,37 @@ What's New
2 2
3This is just a bug-fix/update release. 3This is just a bug-fix/update release.
4 4
5 * Fixed: manual links to home.html changed to index.html (Robert Hahn) 5 * Fixed: manual sample of HTTP authentication now uses correct
6 * Fixed: mime.unb64() returns empty string on results that start 6 "authorization" header (Alexandre Ittner);
7 with a null character (Robert Raschke) 7 * Fixed: failure on bind() was destroying the socket (Sam Roberts);
8 * Fixed: HTTP now automatically redirecting on 303 and 307 (Jonathan Gray) 8 * Fixed: receive() returns immediatelly if prefix can satisfy
9 * Fixed: sleep(-1) could sleep forever wasting CPU. Now it 9 bytes requested (M Joonas Pihlaja);
10 returns immediately (MPB); 10 * Fixed: multicast didn't work on Windows, or anywhere
11 else for that matter (Herbert Leuwer, Adrian Sietsma);
12 * Fixed: select() now reports an error when called with more
13 sockets than FD_SETSIZE (Lorenzo Leonini);
14 * Fixed: manual links to home.html changed to index.html (Robert Hahn);
15 * Fixed: mime.unb64() would return an empty string on results that started
16 with a null character (Robert Raschke);
17 * Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
18 * Fixed: calling sleep() with negative numbers could
19 block forever, wasting CPU. Now it returns immediately (MPB);
20 * Improved: FTP commands are now sent in upper case to
21 help buggy servers (Anders Eurenius);
22 * Improved: known headers now sent in canonic
23 capitalization to help buggy servers (Joseph Stewart);
24 * Improved: Clarified tcp:receive() in the manual (MPB);
25 * Improved: Decent makefiles (LHF).
26 * Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
11 27
12 * Improved: FTP commands are now sent in upper case to
13 help buggy servers (Anders Eurenius)
14 * Improved: known headers now sent in canonic
15 capitalization to help buggy servers (Joseph Stewart);
16 * Improved: Clarified tcp:receive() in the manual (MPB);
17 28
18 * Fixed: multicast didn't work on Windows (Herbert Leuwer, Adrian Sietsma) 29 Yuri's bug?
19 * Fixed: select() reports an error when called with more 30 Dahlberg
20 sockets than FD_SETSIZE (Lorenzo Leonini) 31 Sam Roberts
32 Thomas Harning Jr.
33 Sebastien Perin
34 remove getn in all files
35 ltn12.pump.all(
36 ltn12.source.file(io.open("original.png")),
37 ltn12.sink.file(io.open("copy.png", "wb"))
38 )
diff --git a/doc/ftp.html b/doc/ftp.html
index 1f6335e..3f23a4a 100644
--- a/doc/ftp.html
+++ b/doc/ftp.html
@@ -42,7 +42,7 @@
42FTP (File Transfer Protocol) is a protocol used to transfer files 42FTP (File Transfer Protocol) is a protocol used to transfer files
43between hosts. The <tt>ftp</tt> namespace offers thorough support 43between hosts. The <tt>ftp</tt> namespace offers thorough support
44to FTP, under a simple interface. The implementation conforms to 44to FTP, under a simple interface. The implementation conforms to
45<a href="http://www.cs.princeton.edu/~diego/rfc/rfc0959.txt">RFC 959</a>. 45<a href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</a>.
46</p> 46</p>
47 47
48<p> 48<p>
@@ -70,8 +70,8 @@ local ftp = require("socket.ftp")
70 70
71<p> 71<p>
72URLs MUST conform to 72URLs MUST conform to
73<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC 73<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
741738</a>, that is, an URL is a string in the form: 74that is, an URL is a string in the form:
75</p> 75</p>
76 76
77<blockquote> 77<blockquote>
diff --git a/doc/http.html b/doc/http.html
index a274aef..66282a4 100644
--- a/doc/http.html
+++ b/doc/http.html
@@ -45,8 +45,7 @@ namespace offers full support for the client side of the HTTP
45protocol (i.e., 45protocol (i.e.,
46the facilities that would be used by a web-browser implementation). The 46the facilities that would be used by a web-browser implementation). The
47implementation conforms to the HTTP/1.1 standard, 47implementation conforms to the HTTP/1.1 standard,
48<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC 48<a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
492616</a>.
50</p> 49</p>
51 50
52<p> 51<p>
@@ -67,8 +66,7 @@ local http = require("socket.http")
67 66
68<p> 67<p>
69URLs must conform to 68URLs must conform to
70<a href="http://www.cs.princeton.edu/~diego/rfc/rfc1738.txt">RFC 69<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
711738</a>,
72that is, an URL is a string in the form: 70that is, an URL is a string in the form:
73</p> 71</p>
74 72
@@ -199,8 +197,7 @@ it usually returns a message body (a web page informing the
199URL was not found or some other useless page). To make sure the 197URL was not found or some other useless page). To make sure the
200operation was successful, check the returned status <tt>code</tt>. For 198operation was successful, check the returned status <tt>code</tt>. For
201a list of the possible values and their meanings, refer to <a 199a list of the possible values and their meanings, refer to <a
202href="http://www.cs.princeton.edu/~diego/rfc/rfc2616.txt">RFC 200href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
2032616</a>.
204</p> 201</p>
205 202
206<p class=description> 203<p class=description>
@@ -278,7 +275,7 @@ download and return status "401&nbsp;Authentication Required".
278The HTTP/1.1 standard defines two authentication methods: the Basic 275The HTTP/1.1 standard defines two authentication methods: the Basic
279Authentication Scheme and the Digest Authentication Scheme, both 276Authentication Scheme and the Digest Authentication Scheme, both
280explained in detail in 277explained in detail in
281<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2068.txt">RFC 2068</a>. 278<a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>.
282</p> 279</p>
283 280
284<p class=note>The Basic Authentication Scheme sends 281<p class=note>The Basic Authentication Scheme sends
@@ -304,7 +301,7 @@ b, c, h = http.request("http://fulano:silva@www.example.com/private/index.html")
304-- the request directly. 301-- the request directly.
305r, c = http.request { 302r, c = http.request {
306 url = "http://www.example.com/private/index.html", 303 url = "http://www.example.com/private/index.html",
307 headers = { authentication = "Basic " .. (mime.b64("fulano:silva")) } 304 headers = { authorization = "Basic " .. (mime.b64("fulano:silva")) }
308} 305}
309</pre> 306</pre>
310 307
diff --git a/doc/index.html b/doc/index.html
index 5b54c59..665b97b 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -138,18 +138,22 @@ all!
138</p> 138</p>
139 139
140<ul> 140<ul>
141<li> Fixed: manual sample of HTTP authentication now uses correct
142 "authorization" header (Alexandre Ittner);
143<li> Fixed: receive() returns immediatelly if prefix can satisfy
144 bytes requested (M Joonas Pihlaja);
141<li> Fixed: multicast didn't work on Windows, or anywhere 145<li> Fixed: multicast didn't work on Windows, or anywhere
142 else for that matter (Herbert Leuwer, Adrian Sietsma) 146 else for that matter (Herbert Leuwer, Adrian Sietsma);
143<li> Fixed: select() now reports an error when called with more 147<li> Fixed: select() now reports an error when called with more
144 sockets than FD_SETSIZE (Lorenzo Leonini) 148 sockets than FD_SETSIZE (Lorenzo Leonini);
145<li> Fixed: manual links to home.html changed to index.html (Robert Hahn) 149<li> Fixed: manual links to home.html changed to index.html (Robert Hahn);
146<li> Fixed: mime.unb64() would return an empty string on results that started 150<li> Fixed: mime.unb64() would return an empty string on results that started
147 with a null character (Robert Raschke) 151 with a null character (Robert Raschke);
148<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray) 152<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
149<li> Fixed: calling sleep() with negative numbers could 153<li> Fixed: calling sleep() with negative numbers could
150 block forever, wasting CPU. Now it returns immediately (MPB); 154 block forever, wasting CPU. Now it returns immediately (MPB);
151<li> Improved: FTP commands are now sent in upper case to 155<li> Improved: FTP commands are now sent in upper case to
152 help buggy servers (Anders Eurenius) 156 help buggy servers (Anders Eurenius);
153<li> Improved: known headers now sent in canonic 157<li> Improved: known headers now sent in canonic
154 capitalization to help buggy servers (Joseph Stewart); 158 capitalization to help buggy servers (Joseph Stewart);
155<li> Improved: Clarified tcp:receive() in the manual (MPB); 159<li> Improved: Clarified tcp:receive() in the manual (MPB);
diff --git a/doc/mime.html b/doc/mime.html
index 9844744..ae136fd 100644
--- a/doc/mime.html
+++ b/doc/mime.html
@@ -44,11 +44,11 @@ content transfer encodings, such as Base64 and Quoted-Printable.
44It also provides functions to break text into lines and change 44It also provides functions to break text into lines and change
45the end-of-line convention. 45the end-of-line convention.
46MIME is described mainly in 46MIME is described mainly in
47<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2045.txt">RFC 2045</a>, 47<a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
48<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">2046</a>, 48<a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>,
49<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2047</a>, 49<a href="http://www.ietf.org/rfc/rfc2047.txt">2047</a>,
50<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2047.txt">2048</a>, and 50<a href="http://www.ietf.org/rfc/rfc2047.txt">2048</a>, and
51<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2048.txt">2049</a>. 51<a href="http://www.ietf.org/rfc/rfc2048.txt">2049</a>.
52</p> 52</p>
53 53
54<p> 54<p>
diff --git a/doc/smtp.html b/doc/smtp.html
index 980b821..2ef673a 100644
--- a/doc/smtp.html
+++ b/doc/smtp.html
@@ -48,14 +48,13 @@ control (if you bother to read the code).
48</p> 48</p>
49 49
50<p>The implementation conforms to the Simple Mail Transfer Protocol, 50<p>The implementation conforms to the Simple Mail Transfer Protocol,
51<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a>. 51<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>.
52Another RFC of interest is <a 52Another RFC of interest is <a
53href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>, 53href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>,
54which governs the Internet Message Format. 54which governs the Internet Message Format.
55Multipart messages (those that contain attachments) are part 55Multipart messages (those that contain attachments) are part
56of the MIME standard, but described mainly 56of the MIME standard, but described mainly
57in <a href="http://www.cs.princeton.edu/~diego/rfc/rfc2046.txt">RFC 57in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>
582046</a>
59 58
60<p> In the description below, good understanding of <a 59<p> In the description below, good understanding of <a
61href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters 60href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
@@ -196,7 +195,7 @@ part of the message and will not be sent to anyone.
196</p> 195</p>
197 196
198<p class=note> 197<p class=note>
199<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a> 198<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>
200has two <em>important and short</em> sections, "3.6.3. Destination address 199has two <em>important and short</em> sections, "3.6.3. Destination address
201fields" and "5. Security considerations", explaining the proper 200fields" and "5. Security considerations", explaining the proper
202use of these headers. Here is a summary of what it says: 201use of these headers. Here is a summary of what it says:
@@ -236,9 +235,9 @@ exactly what you <em>don't</em> want to happen!
236 235
237<p class=note> 236<p class=note>
238I hope this clarifies the issue. Otherwise, please refer to 237I hope this clarifies the issue. Otherwise, please refer to
239<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2821.txt">RFC 2821</a> 238<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>
240and 239and
241<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2822.txt">RFC 2822</a>. 240<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>.
242</p> 241</p>
243 242
244<pre class=example> 243<pre class=example>
diff --git a/doc/url.html b/doc/url.html
index 303e05d..9f234d9 100644
--- a/doc/url.html
+++ b/doc/url.html
@@ -42,8 +42,7 @@
42The <tt>url</tt> namespace provides functions to parse, protect, 42The <tt>url</tt> namespace provides functions to parse, protect,
43and build URLs, as well as functions to compose absolute URLs 43and build URLs, as well as functions to compose absolute URLs
44from base and relative URLs, according to 44from base and relative URLs, according to
45<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2396.txt">RFC 45<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
462396</a>.
47</p> 46</p>
48 47
49<p> 48<p>
@@ -91,7 +90,7 @@ The function returns a string with the absolute URL.
91<p class=note> 90<p class=note>
92Note: The rules that 91Note: The rules that
93govern the composition are fairly complex, and are described in detail in 92govern the composition are fairly complex, and are described in detail in
94<a href="http://www.cs.princeton.edu/~diego/rfc/rfc2396.txt">RFC 2396</a>. 93<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
95The example bellow should give an idea of what the rules are. 94The example bellow should give an idea of what the rules are.
96</p> 95</p>
97 96
diff --git a/etc/dict.lua b/etc/dict.lua
index 5c85aae..6eb3210 100644
--- a/etc/dict.lua
+++ b/etc/dict.lua
@@ -44,48 +44,48 @@ function metat.__index:check(ok)
44end 44end
45 45
46function metat.__index:getdef() 46function metat.__index:getdef()
47 local line = socket.try(self.tp:receive()) 47 local line = socket.try(self.tp:receive())
48 local def = {} 48 local def = {}
49 while line ~= "." do 49 while line ~= "." do
50 table.insert(def, line) 50 table.insert(def, line)
51 line = socket.try(self.tp:receive()) 51 line = socket.try(self.tp:receive())
52 end 52 end
53 return table.concat(def, "\n") 53 return table.concat(def, "\n")
54end 54end
55 55
56function metat.__index:define(database, word) 56function metat.__index:define(database, word)
57 database = database or "!" 57 database = database or "!"
58 socket.try(self.tp:command("DEFINE", database .. " " .. word)) 58 socket.try(self.tp:command("DEFINE", database .. " " .. word))
59 local code, count = self:check(150) 59 local code, count = self:check(150)
60 local defs = {} 60 local defs = {}
61 for i = 1, count do 61 for i = 1, count do
62 self:check(151) 62 self:check(151)
63 table.insert(defs, self:getdef()) 63 table.insert(defs, self:getdef())
64 end 64 end
65 self:check(250) 65 self:check(250)
66 return defs 66 return defs
67end 67end
68 68
69function metat.__index:match(database, strat, word) 69function metat.__index:match(database, strat, word)
70 database = database or "!" 70 database = database or "!"
71 strat = strat or "." 71 strat = strat or "."
72 socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word)) 72 socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word))
73 self:check(152) 73 self:check(152)
74 local mat = {} 74 local mat = {}
75 local line = socket.try(self.tp:receive()) 75 local line = socket.try(self.tp:receive())
76 while line ~= '.' do 76 while line ~= '.' do
77 database, word = socket.skip(2, string.find(line, "(%S+) (.*)")) 77 database, word = socket.skip(2, string.find(line, "(%S+) (.*)"))
78 if not mat[database] then mat[database] = {} end 78 if not mat[database] then mat[database] = {} end
79 table.insert(mat[database], word) 79 table.insert(mat[database], word)
80 line = socket.try(self.tp:receive()) 80 line = socket.try(self.tp:receive())
81 end 81 end
82 self:check(250) 82 self:check(250)
83 return mat 83 return mat
84end 84end
85 85
86function metat.__index:quit() 86function metat.__index:quit()
87 self.tp:command("QUIT") 87 self.tp:command("QUIT")
88 return self:check(221) 88 return self:check(221)
89end 89end
90 90
91function metat.__index:close() 91function metat.__index:close()
diff --git a/etc/get.lua b/etc/get.lua
index 09f639d..0d631c2 100644
--- a/etc/get.lua
+++ b/etc/get.lua
@@ -12,53 +12,53 @@ local ltn12 = require("ltn12")
12 12
13-- formats a number of seconds into human readable form 13-- formats a number of seconds into human readable form
14function nicetime(s) 14function nicetime(s)
15 local l = "s" 15 local l = "s"
16 if s > 60 then 16 if s > 60 then
17 s = s / 60 17 s = s / 60
18 l = "m" 18 l = "m"
19 if s > 60 then 19 if s > 60 then
20 s = s / 60 20 s = s / 60
21 l = "h" 21 l = "h"
22 if s > 24 then 22 if s > 24 then
23 s = s / 24 23 s = s / 24
24 l = "d" -- hmmm 24 l = "d" -- hmmm
25 end 25 end
26 end 26 end
27 end 27 end
28 if l == "s" then return string.format("%5.0f%s", s, l) 28 if l == "s" then return string.format("%5.0f%s", s, l)
29 else return string.format("%5.2f%s", s, l) end 29 else return string.format("%5.2f%s", s, l) end
30end 30end
31 31
32-- formats a number of bytes into human readable form 32-- formats a number of bytes into human readable form
33function nicesize(b) 33function nicesize(b)
34 local l = "B" 34 local l = "B"
35 if b > 1024 then 35 if b > 1024 then
36 b = b / 1024 36 b = b / 1024
37 l = "KB" 37 l = "KB"
38 if b > 1024 then 38 if b > 1024 then
39 b = b / 1024 39 b = b / 1024
40 l = "MB" 40 l = "MB"
41 if b > 1024 then 41 if b > 1024 then
42 b = b / 1024 42 b = b / 1024
43 l = "GB" -- hmmm 43 l = "GB" -- hmmm
44 end 44 end
45 end 45 end
46 end 46 end
47 return string.format("%7.2f%2s", b, l) 47 return string.format("%7.2f%2s", b, l)
48end 48end
49 49
50-- returns a string with the current state of the download 50-- returns a string with the current state of the download
51local remaining_s = "%s received, %s/s throughput, %2.0f%% done, %s remaining" 51local remaining_s = "%s received, %s/s throughput, %2.0f%% done, %s remaining"
52local elapsed_s = "%s received, %s/s throughput, %s elapsed " 52local 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
63 63
64-- creates a new instance of a receive_cb that saves to disk 64-- creates a new instance of a receive_cb that saves to disk
@@ -89,10 +89,10 @@ end
89 89
90-- determines the size of a http file 90-- determines the size of a http file
91function gethttpsize(u) 91function gethttpsize(u)
92 local r, c, h = http.request {method = "HEAD", url = u} 92 local r, c, h = http.request {method = "HEAD", url = u}
93 if c == 200 then 93 if c == 200 then
94 return tonumber(h["content-length"]) 94 return tonumber(h["content-length"])
95 end 95 end
96end 96end
97 97
98-- downloads a file using the http protocol 98-- downloads a file using the http protocol
@@ -101,7 +101,7 @@ function getbyhttp(u, file)
101 -- only print feedback if output is not stdout 101 -- only print feedback if output is not stdout
102 if file then save = ltn12.sink.chain(stats(gethttpsize(u)), save) end 102 if file then save = ltn12.sink.chain(stats(gethttpsize(u)), save) end
103 local r, c, h, s = http.request {url = u, sink = save } 103 local r, c, h, s = http.request {url = u, sink = save }
104 if c ~= 200 then io.stderr:write(s or c, "\n") end 104 if c ~= 200 then io.stderr:write(s or c, "\n") end
105end 105end
106 106
107-- downloads a file using the ftp protocol 107-- downloads a file using the ftp protocol
@@ -114,29 +114,29 @@ function getbyftp(u, file)
114 gett.sink = save 114 gett.sink = save
115 gett.type = "i" 115 gett.type = "i"
116 local ret, err = ftp.get(gett) 116 local ret, err = ftp.get(gett)
117 if err then print(err) end 117 if err then print(err) end
118end 118end
119 119
120-- determines the scheme 120-- determines the scheme
121function getscheme(u) 121function getscheme(u)
122 -- this is an heuristic to solve a common invalid url poblem 122 -- this is an heuristic to solve a common invalid url poblem
123 if not string.find(u, "//") then u = "//" .. u end 123 if not string.find(u, "//") then u = "//" .. u end
124 local parsed = url.parse(u, {scheme = "http"}) 124 local parsed = url.parse(u, {scheme = "http"})
125 return parsed.scheme 125 return parsed.scheme
126end 126end
127 127
128-- gets a file either by http or ftp, saving as <name> 128-- gets a file either by http or ftp, saving as <name>
129function get(u, name) 129function get(u, name)
130 local fout = name and io.open(name, "wb") 130 local fout = name and io.open(name, "wb")
131 local scheme = getscheme(u) 131 local scheme = getscheme(u)
132 if scheme == "ftp" then getbyftp(u, fout) 132 if scheme == "ftp" then getbyftp(u, fout)
133 elseif scheme == "http" then getbyhttp(u, fout) 133 elseif scheme == "http" then getbyhttp(u, fout)
134 else print("unknown scheme" .. scheme) end 134 else print("unknown scheme" .. scheme) end
135end 135end
136 136
137-- main program 137-- main program
138arg = arg or {} 138arg = arg or {}
139if table.getn(arg) < 1 then 139if table.getn(arg) < 1 then
140 io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n") 140 io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
141 os.exit(1) 141 os.exit(1)
142else get(arg[1], arg[2]) end 142else get(arg[1], arg[2]) end
diff --git a/etc/lp.lua b/etc/lp.lua
index 3757e2d..f067604 100644
--- a/etc/lp.lua
+++ b/etc/lp.lua
@@ -268,11 +268,11 @@ send = socket.protect(function(option)
268 local class = string.sub(option.class or localip or localhost,1,31) 268 local class = string.sub(option.class or localip or localhost,1,31)
269 local _,_,ctlfn = string.find(file,".*[%/%\\](.*)") 269 local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
270 ctlfn = string.sub(ctlfn or file,1,131) 270 ctlfn = string.sub(ctlfn or file,1,131)
271 local cfile = 271 local cfile =
272 string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n", 272 string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
273 localhost, 273 localhost,
274 class, 274 class,
275 option.job or "LuaSocket", 275 option.job or "LuaSocket",
276 user, 276 user,
277 fmt, lpfile, 277 fmt, lpfile,
278 lpfile, 278 lpfile,
diff --git a/etc/tftp.lua b/etc/tftp.lua
index c028b20..4051e74 100644
--- a/etc/tftp.lua
+++ b/etc/tftp.lua
@@ -35,18 +35,18 @@ local OP_INV = {"RRQ", "WRQ", "DATA", "ACK", "ERROR"}
35-- Packet creation functions 35-- Packet creation functions
36----------------------------------------------------------------------------- 36-----------------------------------------------------------------------------
37local function RRQ(source, mode) 37local function RRQ(source, mode)
38 return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0) 38 return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
39end 39end
40 40
41local function WRQ(source, mode) 41local function WRQ(source, mode)
42 return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0) 42 return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
43end 43end
44 44
45local function ACK(block) 45local 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)
@@ -58,16 +58,16 @@ end
58-- Packet analysis functions 58-- Packet analysis functions
59----------------------------------------------------------------------------- 59-----------------------------------------------------------------------------
60local function split_DATA(dgram) 60local function split_DATA(dgram)
61 local block = byte(dgram, 3)*256 + byte(dgram, 4) 61 local block = byte(dgram, 3)*256 + byte(dgram, 4)
62 local data = string.sub(dgram, 5) 62 local data = string.sub(dgram, 5)
63 return block, data 63 return block, data
64end 64end
65 65
66local function get_ERROR(dgram) 66local function get_ERROR(dgram)
67 local code = byte(dgram, 3)*256 + byte(dgram, 4) 67 local code = byte(dgram, 3)*256 + byte(dgram, 4)
68 local msg 68 local msg
69 _,_, msg = string.find(dgram, "(.*)\000", 5) 69 _,_, msg = string.find(dgram, "(.*)\000", 5)
70 return string.format("error code %d: %s", code, msg) 70 return string.format("error code %d: %s", code, msg)
71end 71end
72 72
73----------------------------------------------------------------------------- 73-----------------------------------------------------------------------------
@@ -77,40 +77,40 @@ local function tget(gett)
77 local retries, dgram, sent, datahost, dataport, code 77 local retries, dgram, sent, datahost, dataport, code
78 local last = 0 78 local last = 0
79 socket.try(gett.host, "missing host") 79 socket.try(gett.host, "missing host")
80 local con = socket.try(socket.udp()) 80 local con = socket.try(socket.udp())
81 local try = socket.newtry(function() con:close() end) 81 local try = socket.newtry(function() con:close() end)
82 -- convert from name to ip if needed 82 -- convert from name to ip if needed
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
98 local sink = gett.sink or ltn12.sink.null() 98 local sink = gett.sink or ltn12.sink.null()
99 -- process all data packets 99 -- process all data packets
100 while 1 do 100 while 1 do
101 -- decode packet 101 -- decode packet
102 code = get_OP(dgram) 102 code = get_OP(dgram)
103 try(code ~= OP_ERROR, get_ERROR(dgram)) 103 try(code ~= OP_ERROR, get_ERROR(dgram))
104 try(code == OP_DATA, "unhandled opcode " .. code) 104 try(code == OP_DATA, "unhandled opcode " .. code)
105 -- get data packet parts 105 -- get data packet parts
106 local block, data = split_DATA(dgram) 106 local block, data = split_DATA(dgram)
107 -- if not repeated, write 107 -- if not repeated, write
108 if block == last+1 then 108 if block == last+1 then
109 try(sink(data)) 109 try(sink(data))
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,13 +118,13 @@ 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
125 until dgram or err ~= "timeout" or retries > 5 125 until dgram or err ~= "timeout" or retries > 5
126 try(dgram, err) 126 try(dgram, err)
127 end 127 end
128end 128end
129 129
130local default = { 130local default = {
diff --git a/makefile b/makefile
index a9ce34d..4275474 100644
--- a/makefile
+++ b/makefile
@@ -1,21 +1,13 @@
1PLAT= none 1PLAT?= macosx
2PLATS= macosx linux 2PLATS= macosx linux win32
3 3
4#------ 4#------
5# Hopefully no need to change anything below this line 5# Hopefully no need to change anything below this line
6# 6#
7all: $(PLAT) 7all: $(PLAT)
8 8
9none: 9$(PLATS) none install local clean:
10 @echo "Please run" 10 @cd src; $(MAKE) $@
11 @echo " make PLATFORM"
12 @echo "where PLATFORM is one of these:"
13 @echo " $(PLATS)"
14
15$(PLATS) install local clean:
16 cd src; $(MAKE) $@
17
18dummy:
19 11
20test: dummy 12test: dummy
21 lua test/hello.lua 13 lua test/hello.lua
diff --git a/src/buffer.c b/src/buffer.c
index 363da3d..5be0faf 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -42,7 +42,7 @@ int buffer_open(lua_State *L) {
42* Initializes C structure 42* Initializes C structure
43\*-------------------------------------------------------------------------*/ 43\*-------------------------------------------------------------------------*/
44void buffer_init(p_buffer buf, p_io io, p_timeout tm) { 44void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
45 buf->first = buf->last = 0; 45 buf->first = buf->last = 0;
46 buf->io = io; 46 buf->io = io;
47 buf->tm = tm; 47 buf->tm = tm;
48 buf->received = buf->sent = 0; 48 buf->received = buf->sent = 0;
@@ -122,9 +122,15 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
122 if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); 122 if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
123 else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); 123 else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
124 else luaL_argcheck(L, 0, 2, "invalid receive pattern"); 124 else luaL_argcheck(L, 0, 2, "invalid receive pattern");
125 /* get a fixed number of bytes (minus what was already partially 125 /* get a fixed number of bytes (minus what was already partially
126 * received) */ 126 * received) */
127 } else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b); 127 } else {
128 double n = lua_tonumber(L, 2);
129 size_t wanted = (size_t) n;
130 luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
131 if (size == 0 || wanted > size)
132 err = recvraw(buf, wanted-size, &b);
133 }
128 /* check if there was an error */ 134 /* check if there was an error */
129 if (err != IO_DONE) { 135 if (err != IO_DONE) {
130 /* we can't push anyting in the stack before pushing the 136 /* we can't push anyting in the stack before pushing the
diff --git a/src/buffer.h b/src/buffer.h
index 58838d1..1281bb3 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -29,8 +29,8 @@ typedef struct t_buffer_ {
29 size_t sent, received; /* bytes sent, and bytes received */ 29 size_t sent, received; /* bytes sent, and bytes received */
30 p_io io; /* IO driver used for this buffer */ 30 p_io io; /* IO driver used for this buffer */
31 p_timeout tm; /* timeout management for this buffer */ 31 p_timeout tm; /* timeout management for this buffer */
32 size_t first, last; /* index of first and last bytes of stored data */ 32 size_t first, last; /* index of first and last bytes of stored data */
33 char data[BUF_SIZE]; /* storage space for buffer data */ 33 char data[BUF_SIZE]; /* storage space for buffer data */
34} t_buffer; 34} t_buffer;
35typedef t_buffer *p_buffer; 35typedef t_buffer *p_buffer;
36 36
diff --git a/src/ftp.lua b/src/ftp.lua
index f27e838..c90a65c 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -212,8 +212,8 @@ local function tput(putt)
212end 212end
213 213
214local default = { 214local default = {
215 path = "/", 215 path = "/",
216 scheme = "ftp" 216 scheme = "ftp"
217} 217}
218 218
219local function parse(u) 219local function parse(u)
diff --git a/src/inet.c b/src/inet.c
index 32f0cd2..862288c 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -213,7 +213,7 @@ const char *inet_tryconnect(p_socket ps, const char *address,
213 memset(&remote, 0, sizeof(remote)); 213 memset(&remote, 0, sizeof(remote));
214 remote.sin_family = AF_INET; 214 remote.sin_family = AF_INET;
215 remote.sin_port = htons(port); 215 remote.sin_port = htons(port);
216 if (strcmp(address, "*")) { 216 if (strcmp(address, "*")) {
217 if (!inet_aton(address, &remote.sin_addr)) { 217 if (!inet_aton(address, &remote.sin_addr)) {
218 struct hostent *hp = NULL; 218 struct hostent *hp = NULL;
219 struct in_addr **addr; 219 struct in_addr **addr;
@@ -248,7 +248,6 @@ const char *inet_trybind(p_socket ps, const char *address, unsigned short port)
248 memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); 248 memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
249 } 249 }
250 err = socket_bind(ps, (SA *) &local, sizeof(local)); 250 err = socket_bind(ps, (SA *) &local, sizeof(local));
251 if (err != IO_DONE) socket_destroy(ps);
252 return socket_strerror(err); 251 return socket_strerror(err);
253} 252}
254 253
diff --git a/src/makefile b/src/makefile
index 3351997..701feb3 100644
--- a/src/makefile
+++ b/src/makefile
@@ -1,8 +1,13 @@
1PLAT = none 1PLAT?=macosx
2
2INSTALL_DATA=cp 3INSTALL_DATA=cp
3INSTALL_EXEC=cp 4INSTALL_EXEC=cp
4INSTALL_TOP= /opt/local 5INSTALL_TOP=/opt/local
5LUAINC= $(LUAINC_$(PLAT)) 6
7LUAINC_macosx=/opt/local/include
8LUAINC_linux=/usr/include/lua5.1
9LUAINC_win32="../../lua-5.1.3/src"
10LUALIB_win32="../../lua-5.1.3"
6 11
7#------ 12#------
8# Install directories 13# Install directories
@@ -15,40 +20,76 @@ INSTALL_MIME_SHARE=$(INSTALL_TOP_SHARE)/mime
15INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime 20INSTALL_MIME_LIB=$(INSTALL_TOP_LIB)/mime
16 21
17#------ 22#------
18# Output file names 23# Supported platforms
19# 24#
20EXT=so 25PLATS= macosx linux win32
21SOCKET_V=2.0.3
22MIME_V=1.0.3
23SOCKET_SO=socket.$(EXT).$(SOCKET_V)
24MIME_SO=mime.$(EXT).$(MIME_V)
25UNIX_SO=unix.$(EXT)
26 26
27#------ 27#------
28# Compiler and linker settings 28# Compiler and linker settings
29# for Mac OS X 29# for Mac OS X
30LUAINC_macosx= -I/opt/local/include 30SO_macosx=so
31O_macosx=o
31CC_macosx=gcc 32CC_macosx=gcc
32DEF_macosx= -DLUASOCKET_DEBUG -DUNIX_HAS_SUN_LEN \ 33DEF_macosx= -DLUASOCKET_DEBUG -DUNIX_HAS_SUN_LEN \
33 -DLUASOCKET_API='__attribute__((visibility("default")))' \ 34 -DLUASOCKET_API='__attribute__((visibility("default")))' \
34 -DMIME_API='__attribute__((visibility("default")))' 35 -DMIME_API='__attribute__((visibility("default")))'
35CFLAGS_macosx= $(LUAINC) $(COMPAT) $(DEF) -pedantic -Wall -O2 -fno-common \ 36CFLAGS_macosx= -I$(LUAINC) $(DEF) -pedantic -Wall -O2 -fno-common \
36 -fvisibility=hidden 37 -fvisibility=hidden
37LDFLAGS_macosx= -bundle -undefined dynamic_lookup 38LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o
38LD_macosx= export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc 39LD_macosx= export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc
40SOCKET_macosx=usocket.o
39 41
40#------ 42#------
41# Compiler and linker settings 43# Compiler and linker settings
42# for Linux 44# for Linux
43LUAINC_linux= -I/usr/local/include/lua5.1 45SO_linux=so
46O_linux=o
44CC_linux=gcc 47CC_linux=gcc
45DEF_linux=-DLUASOCKET_DEBUG \ 48DEF_linux=-DLUASOCKET_DEBUG \
46 -DLUASOCKET_API='__attribute__((visibility("default")))' \ 49 -DLUASOCKET_API='__attribute__((visibility("default")))' \
47 -DMIME_API='__attribute__((visibility("default")))' 50 -DMIME_API='__attribute__((visibility("default")))'
48CFLAGS_linux= $(LUAINC) $(DEF) -pedantic -Wall -O2 -fpic \ 51CFLAGS_linux= -I$(LUAINC) $(DEF) -pedantic -Wall -O2 -fpic \
49 -fvisibility=hidden 52 -fvisibility=hidden
50LDFLAGS_linux=-O -shared -fpic 53LDFLAGS_linux=-O -shared -fpic -o
51LD_linux= gcc 54LD_linux=gcc
55SOCKET_linux=usocket.o
56
57#------
58# Compiler and linker settings
59# for Win32
60SO_win32=dll
61O_win32=obj
62CC_win32=cl
63DEF_win32= /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" \
64 /D "LUASOCKET_API=__declspec(dllexport)" /D "LUASOCKET_DEBUG" \
65 /D "_CRT_SECURE_NO_WARNINGS" /D "_WINDLL"
66CFLAGS_win32=/I$(LUAINC) $(DEF) /O2 /Ot /MD /W3 /nologo
67LDFLAGS_win32= /nologo /link /NOLOGO /DLL /INCREMENTAL:NO \
68 /LIBPATH:$(LUALIB) \
69 /MANIFEST \
70 /MANIFESTFILE:"intermediate.manifest" \
71 /MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
72 /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /DYNAMICBASE:NO \
73 /MACHINE:X86 ws2_32.lib lua5.1.lib /OUT:
74LD_win32=cl
75SOCKET_win32=wsocket.obj
76
77.SUFFIXES: .obj
78
79.c.obj:
80 $(CC) $(CFLAGS) /Fo"$@" /c $<
81
82#------
83# Output file names
84#
85SO=$(SO_$(PLAT))
86O=$(O_$(PLAT))
87SOCKET_V=2.0.3
88MIME_V=1.0.3
89SOCKET_SO=socket.$(SO).$(SOCKET_V)
90MIME_SO=mime.$(SO).$(MIME_V)
91UNIX_SO=unix.$(SO)
92SOCKET=$(SOCKET_$(PLAT))
52 93
53#------ 94#------
54# Settings selected for platform 95# Settings selected for platform
@@ -58,46 +99,48 @@ DEF=$(DEF_$(PLAT))
58CFLAGS=$(CFLAGS_$(PLAT)) 99CFLAGS=$(CFLAGS_$(PLAT))
59LDFLAGS=$(LDFLAGS_$(PLAT)) 100LDFLAGS=$(LDFLAGS_$(PLAT))
60LD=$(LD_$(PLAT)) 101LD=$(LD_$(PLAT))
102LUAINC= $(LUAINC_$(PLAT))
103LUALIB= $(LUALIB_$(PLAT))
61 104
62#------ 105#------
63# Modules belonging to socket-core 106# Modules belonging to socket-core
64# 107#
65SOCKET_OBJS= \ 108SOCKET_OBJS= \
66 luasocket.o \ 109 luasocket.$(O) \
67 timeout.o \ 110 timeout.$(O) \
68 buffer.o \ 111 buffer.$(O) \
69 io.o \ 112 io.$(O) \
70 auxiliar.o \ 113 auxiliar.$(O) \
71 options.o \ 114 options.$(O) \
72 inet.o \ 115 inet.$(O) \
73 usocket.o \ 116 $(SOCKET) \
74 except.o \ 117 except.$(O) \
75 select.o \ 118 select.$(O) \
76 tcp.o \ 119 tcp.$(O) \
77 udp.o 120 udp.$(O)
78 121
79#------ 122#------
80# Modules belonging mime-core 123# Modules belonging mime-core
81# 124#
82MIME_OBJS= \ 125MIME_OBJS= \
83 mime.o 126 mime.$(O)
84 127
85#------ 128#------
86# Modules belonging unix (local domain sockets) 129# Modules belonging unix (local domain sockets)
87# 130#
88UNIX_OBJS:=\ 131UNIX_OBJS=\
89 buffer.o \ 132 buffer.$(O) \
90 auxiliar.o \ 133 auxiliar.$(O) \
91 options.o \ 134 options.$(O) \
92 timeout.o \ 135 timeout.$(O) \
93 io.o \ 136 io.$(O) \
94 usocket.o \ 137 usocket.$(O) \
95 unix.o 138 unix.$(O)
96 139
97#------ 140#------
98# Files to install 141# Files to install
99# 142#
100TO_SOCKET_SHARE:= \ 143TO_SOCKET_SHARE= \
101 http.lua \ 144 http.lua \
102 url.lua \ 145 url.lua \
103 tp.lua \ 146 tp.lua \
@@ -105,33 +148,41 @@ TO_SOCKET_SHARE:= \
105 headers.lua \ 148 headers.lua \
106 smtp.lua 149 smtp.lua
107 150
108TO_TOP_SHARE:= \ 151TO_TOP_SHARE= \
109 ltn12.lua \ 152 ltn12.lua \
110 socket.lua \ 153 socket.lua \
111 mime.lua 154 mime.lua
112 155
156#------
157# Targets
158#
113default: $(PLAT) 159default: $(PLAT)
114 160
115macosx: 161macosx:
116 $(MAKE) all PLAT=macosx 162 $(MAKE) all PLAT=macosx
117 163
164win32:
165 $(MAKE) all PLAT=win32
166
118linux: 167linux:
119 $(MAKE) all PLAT=linux 168 $(MAKE) all PLAT=linux
120 169
121none: 170none:
122 @echo "Please choose a platform:" 171 @echo "Please run"
172 @echo " make PLATFORM"
173 @echo "where PLATFORM is one of these:"
123 @echo " $(PLATS)" 174 @echo " $(PLATS)"
124 175
125all: $(SOCKET_SO) $(MIME_SO) 176all: $(SOCKET_SO) $(MIME_SO)
126 177
127$(SOCKET_SO): $(SOCKET_OBJS) 178$(SOCKET_SO): $(SOCKET_OBJS)
128 $(LD) $(LDFLAGS) -o $@ $(SOCKET_OBJS) 179 $(LD) $(SOCKET_OBJS) $(LDFLAGS)$@
129 180
130$(MIME_SO): $(MIME_OBJS) 181$(MIME_SO): $(MIME_OBJS)
131 $(LD) $(LDFLAGS) -o $@ $(MIME_OBJS) 182 $(LD) $(MIME_OBJS) $(LDFLAGS)$@
132 183
133$(UNIX_SO): $(UNIX_OBJS) 184$(UNIX_SO): $(UNIX_OBJS)
134 $(LD) $(LDFLAGS) -o $@ $(UNIX_OBJS) 185 $(LD) $(UNIX_OBJS) $(LDFLAGS)$@
135 186
136install: 187install:
137 mkdir -p $(INSTALL_TOP_SHARE) 188 mkdir -p $(INSTALL_TOP_SHARE)
@@ -139,9 +190,9 @@ install:
139 mkdir -p $(INSTALL_SOCKET_SHARE) 190 mkdir -p $(INSTALL_SOCKET_SHARE)
140 $(INSTALL_DATA) $(TO_SOCKET_SHARE) $(INSTALL_SOCKET_SHARE) 191 $(INSTALL_DATA) $(TO_SOCKET_SHARE) $(INSTALL_SOCKET_SHARE)
141 mkdir -p $(INSTALL_SOCKET_LIB) 192 mkdir -p $(INSTALL_SOCKET_LIB)
142 $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(EXT) 193 $(INSTALL_EXEC) $(SOCKET_SO) $(INSTALL_SOCKET_LIB)/core.$(SO)
143 mkdir -p $(INSTALL_MIME_LIB) 194 mkdir -p $(INSTALL_MIME_LIB)
144 $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(EXT) 195 $(INSTALL_EXEC) $(MIME_SO) $(INSTALL_MIME_LIB)/core.$(SO)
145 196
146local: 197local:
147 $(MAKE) install INSTALL_TOP_LIB=.. INSTALL_TOP_SHARE=.. 198 $(MAKE) install INSTALL_TOP_LIB=.. INSTALL_TOP_SHARE=..
@@ -155,24 +206,24 @@ clean:
155#------ 206#------
156# List of dependencies 207# List of dependencies
157# 208#
158auxiliar.o: auxiliar.c auxiliar.h 209auxiliar.$(O): auxiliar.c auxiliar.h
159buffer.o: buffer.c buffer.h io.h timeout.h 210buffer.$(O): buffer.c buffer.h io.h timeout.h
160except.o: except.c except.h 211except.$(O): except.c except.h
161inet.o: inet.c inet.h socket.h io.h timeout.h usocket.h 212inet.$(O): inet.c inet.h socket.h io.h timeout.h usocket.h
162io.o: io.c io.h timeout.h 213io.$(O): io.c io.h timeout.h
163luasocket.o: luasocket.c luasocket.h auxiliar.h except.h \ 214luasocket.$(O): luasocket.c luasocket.h auxiliar.h except.h \
164 timeout.h buffer.h io.h inet.h socket.h usocket.h tcp.h \ 215 timeout.h buffer.h io.h inet.h socket.h usocket.h tcp.h \
165 udp.h select.h 216 udp.h select.h
166mime.o: mime.c mime.h 217mime.$(O): mime.c mime.h
167options.o: options.c auxiliar.h options.h socket.h io.h \ 218options.$(O): options.c auxiliar.h options.h socket.h io.h \
168 timeout.h usocket.h inet.h 219 timeout.h usocket.h inet.h
169select.o: select.c socket.h io.h timeout.h usocket.h select.h 220select.$(O): select.c socket.h io.h timeout.h usocket.h select.h
170tcp.o: tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \ 221tcp.$(O): tcp.c auxiliar.h socket.h io.h timeout.h usocket.h \
171 inet.h options.h tcp.h buffer.h 222 inet.h options.h tcp.h buffer.h
172timeout.o: timeout.c auxiliar.h timeout.h 223timeout.$(O): timeout.c auxiliar.h timeout.h
173udp.o: udp.c auxiliar.h socket.h io.h timeout.h usocket.h \ 224udp.$(O): udp.c auxiliar.h socket.h io.h timeout.h usocket.h \
174 inet.h options.h udp.h 225 inet.h options.h udp.h
175unix.o: unix.c auxiliar.h socket.h io.h timeout.h usocket.h \ 226unix.$(O): unix.c auxiliar.h socket.h io.h timeout.h usocket.h \
176 options.h unix.h buffer.h 227 options.h unix.h buffer.h
177usocket.o: usocket.c socket.h io.h timeout.h usocket.h 228usocket.$(O): usocket.c socket.h io.h timeout.h usocket.h
178wsocket.o: wsocket.c socket.h io.h timeout.h usocket.h 229wsocket.$(O): wsocket.c socket.h io.h timeout.h usocket.h
diff --git a/src/mbox.lua b/src/mbox.lua
index ce6537c..b7d4a2a 100644
--- a/src/mbox.lua
+++ b/src/mbox.lua
@@ -5,10 +5,10 @@ mbox = Public
5function Public.split_message(message_s) 5function Public.split_message(message_s)
6 local message = {} 6 local message = {}
7 message_s = string.gsub(message_s, "\r\n", "\n") 7 message_s = string.gsub(message_s, "\r\n", "\n")
8 string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end) 8 string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end)
9 string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end) 9 string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end)
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
@@ -54,30 +54,30 @@ function Public.parse_from(from)
54 name = name or "" 54 name = name or ""
55 address = address or "" 55 address = address or ""
56 if name == "" then name = address end 56 if name == "" then name = address end
57 name = string.gsub(name, '"', "") 57 name = string.gsub(name, '"', "")
58 return name, address 58 return name, address
59end 59end
60 60
61function Public.split_mbox(mbox_s) 61function Public.split_mbox(mbox_s)
62 mbox = {} 62 mbox = {}
63 mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n" 63 mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
64 local nj, i, j = 1, 1, 1 64 local nj, i, j = 1, 1, 1
65 while 1 do 65 while 1 do
66 i, nj = string.find(mbox_s, "\n\nFrom .-\n", j) 66 i, nj = string.find(mbox_s, "\n\nFrom .-\n", j)
67 if not i then break end 67 if not i then break end
68 local message = string.sub(mbox_s, j, i-1) 68 local message = string.sub(mbox_s, j, i-1)
69 table.insert(mbox, message) 69 table.insert(mbox, message)
70 j = nj+1 70 j = nj+1
71 end 71 end
72 return mbox 72 return mbox
73end 73end
74 74
75function Public.parse(mbox_s) 75function Public.parse(mbox_s)
76 local mbox = Public.split_mbox(mbox_s) 76 local mbox = Public.split_mbox(mbox_s)
77 for i = 1, table.getn(mbox) do 77 for i = 1, table.getn(mbox) do
78 mbox[i] = Public.parse_message(mbox[i]) 78 mbox[i] = Public.parse_message(mbox[i])
79 end 79 end
80 return mbox 80 return mbox
81end 81end
82 82
83function Public.parse_message(message_s) 83function Public.parse_message(message_s)
diff --git a/src/tp.lua b/src/tp.lua
index 5fd8d22..46f7f64 100644
--- a/src/tp.lua
+++ b/src/tp.lua
@@ -106,7 +106,7 @@ end
106-- closes the underlying c 106-- closes the underlying c
107function metat.__index:close() 107function metat.__index:close()
108 self.c:close() 108 self.c:close()
109 return 1 109 return 1
110end 110end
111 111
112-- connect with server and return c object 112-- connect with server and return c object
diff --git a/src/url.lua b/src/url.lua
index 18e5ab2..7623557 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -40,25 +40,25 @@ end
40-- escaped representation of string binary 40-- escaped representation of string binary
41----------------------------------------------------------------------------- 41-----------------------------------------------------------------------------
42local function make_set(t) 42local function make_set(t)
43 local s = {} 43 local s = {}
44 for i,v in base.ipairs(t) do 44 for i,v in base.ipairs(t) do
45 s[t[i]] = 1 45 s[t[i]] = 1
46 end 46 end
47 return s 47 return s
48end 48end
49 49
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)
62end 62end
63 63
64----------------------------------------------------------------------------- 64-----------------------------------------------------------------------------
@@ -182,20 +182,26 @@ function build(parsed)
182 local url = build_path(ppath) 182 local url = build_path(ppath)
183 if parsed.params then url = url .. ";" .. parsed.params end 183 if parsed.params then url = url .. ";" .. parsed.params end
184 if parsed.query then url = url .. "?" .. parsed.query end 184 if parsed.query then url = url .. "?" .. parsed.query end
185 local authority = parsed.authority 185 local authority = parsed.authority
186 if parsed.host then 186 if parsed.host then
187 authority = parsed.host 187 authority = parsed.host
188 if parsed.port then authority = authority .. ":" .. parsed.port end 188 if parsed.port then authority = authority .. ":" .. parsed.port end
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
197 end 197 end
198 if authority then url = "//" .. authority .. url end 198 if authority then
199 if string.sub(url, 1, 1) == "/" then
200 url = "//" .. authority .. url
201 else
202 url = "//" .. authority .. "/" .. url
203 end
204 end
199 if parsed.scheme then url = parsed.scheme .. ":" .. url end 205 if parsed.scheme then url = parsed.scheme .. ":" .. url end
200 if parsed.fragment then url = url .. "#" .. parsed.fragment end 206 if parsed.fragment then url = url .. "#" .. parsed.fragment end
201 -- url = string.gsub(url, "%s", "") 207 -- url = string.gsub(url, "%s", "")
@@ -211,8 +217,8 @@ end
211-- corresponding absolute url 217-- corresponding absolute url
212----------------------------------------------------------------------------- 218-----------------------------------------------------------------------------
213function absolute(base_url, relative_url) 219function absolute(base_url, relative_url)
220 local base_parsed = base_url
214 if base.type(base_url) == "table" then 221 if base.type(base_url) == "table" then
215 base_parsed = base_url
216 base_url = build(base_parsed) 222 base_url = build(base_parsed)
217 else 223 else
218 base_parsed = parse(base_url) 224 base_parsed = parse(base_url)
@@ -250,16 +256,16 @@ end
250-- segment: a table with one entry per segment 256-- segment: a table with one entry per segment
251----------------------------------------------------------------------------- 257-----------------------------------------------------------------------------
252function parse_path(path) 258function parse_path(path)
253 local parsed = {} 259 local parsed = {}
254 path = path or "" 260 path = path or ""
255 --path = string.gsub(path, "%s", "") 261 --path = string.gsub(path, "%s", "")
256 string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) 262 string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
257 for i = 1, table.getn(parsed) do 263 for i = 1, table.getn(parsed) do
258 parsed[i] = unescape(parsed[i]) 264 parsed[i] = unescape(parsed[i])
259 end 265 end
260 if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end 266 if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
261 if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end 267 if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
262 return parsed 268 return parsed
263end 269end
264 270
265----------------------------------------------------------------------------- 271-----------------------------------------------------------------------------
@@ -271,27 +277,27 @@ end
271-- path: corresponding path stringing 277-- path: corresponding path stringing
272----------------------------------------------------------------------------- 278-----------------------------------------------------------------------------
273function build_path(parsed, unsafe) 279function build_path(parsed, unsafe)
274 local path = "" 280 local path = ""
275 local n = table.getn(parsed) 281 local n = table.getn(parsed)
276 if unsafe then 282 if unsafe then
277 for i = 1, n-1 do 283 for i = 1, n-1 do
278 path = path .. parsed[i] 284 path = path .. parsed[i]
279 path = path .. "/" 285 path = path .. "/"
280 end 286 end
281 if n > 0 then 287 if n > 0 then
282 path = path .. parsed[n] 288 path = path .. parsed[n]
283 if parsed.is_directory then path = path .. "/" end 289 if parsed.is_directory then path = path .. "/" end
284 end 290 end
285 else 291 else
286 for i = 1, n-1 do 292 for i = 1, n-1 do
287 path = path .. protect_segment(parsed[i]) 293 path = path .. protect_segment(parsed[i])
288 path = path .. "/" 294 path = path .. "/"
289 end 295 end
290 if n > 0 then 296 if n > 0 then
291 path = path .. protect_segment(parsed[n]) 297 path = path .. protect_segment(parsed[n])
292 if parsed.is_directory then path = path .. "/" end 298 if parsed.is_directory then path = path .. "/" end
293 end 299 end
294 end 300 end
295 if parsed.is_absolute then path = "/" .. path end 301 if parsed.is_absolute then path = "/" .. path end
296 return path 302 return path
297end 303end
diff --git a/src/usocket.c b/src/usocket.c
index 2c30b9a..1ba1043 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -30,9 +30,9 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
30 pfd.revents = 0; 30 pfd.revents = 0;
31 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ 31 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
32 do { 32 do {
33 int t = (int)(timeout_getretry(tm)*1e3); 33 int t = (int)(timeout_getretry(tm)*1e3);
34 ret = poll(&pfd, 1, t >= 0? t: -1); 34 ret = poll(&pfd, 1, t >= 0? t: -1);
35 } while (ret == -1 && errno == EINTR); 35 } while (ret == -1 && errno == EINTR);
36 if (ret == -1) return errno; 36 if (ret == -1) return errno;
37 if (ret == 0) return IO_TIMEOUT; 37 if (ret == 0) return IO_TIMEOUT;
38 if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED; 38 if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED;
diff --git a/src/wsocket.c b/src/wsocket.c
index e247777..2d07904 100644
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -54,7 +54,7 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
54 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ 54 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
55 if (sw & WAITFD_R) { 55 if (sw & WAITFD_R) {
56 FD_ZERO(&rfds); 56 FD_ZERO(&rfds);
57 FD_SET(*ps, &rfds); 57 FD_SET(*ps, &rfds);
58 rp = &rfds; 58 rp = &rfds;
59 } 59 }
60 if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } 60 if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
@@ -207,7 +207,7 @@ int socket_send(p_socket ps, const char *data, size_t count,
207 /* loop until we send something or we give up on error */ 207 /* loop until we send something or we give up on error */
208 for ( ;; ) { 208 for ( ;; ) {
209 /* try to send something */ 209 /* try to send something */
210 int put = send(*ps, data, (int) count, 0); 210 int put = send(*ps, data, (int) count, 0);
211 /* if we sent something, we are done */ 211 /* if we sent something, we are done */
212 if (put > 0) { 212 if (put > 0) {
213 *sent = put; 213 *sent = put;
@@ -346,8 +346,8 @@ const char *socket_strerror(int err) {
346} 346}
347 347
348const char *socket_ioerror(p_socket ps, int err) { 348const char *socket_ioerror(p_socket ps, int err) {
349 (void) ps; 349 (void) ps;
350 return socket_strerror(err); 350 return socket_strerror(err);
351} 351}
352 352
353static const char *wstrerror(int err) { 353static const char *wstrerror(int err) {
diff --git a/test/ftptest.lua b/test/ftptest.lua
index f35e16f..fb13326 100644
--- a/test/ftptest.lua
+++ b/test/ftptest.lua
@@ -82,10 +82,10 @@ print("ok")
82io.write("testing parameter overriding: ") 82io.write("testing parameter overriding: ")
83local back = {} 83local back = {}
84ret, err = ftp.get{ 84ret, err = ftp.get{
85 url = "//stupid:mistake@" .. host .. "/index.html", 85 url = "//stupid:mistake@" .. host .. "/index.html",
86 user = "luasocket", 86 user = "luasocket",
87 password = "pedrovian", 87 password = "pedrovian",
88 type = "i", 88 type = "i",
89 sink = ltn12.sink.table(back) 89 sink = ltn12.sink.table(back)
90} 90}
91assert(ret and not err and table.concat(back) == index, err) 91assert(ret and not err and table.concat(back) == index, err)
diff --git a/test/httptest.lua b/test/httptest.lua
index 9d50a14..614acf3 100644
--- a/test/httptest.lua
+++ b/test/httptest.lua
@@ -34,28 +34,28 @@ index_file = "index.html"
34index = readfile(index_file) 34index = readfile(index_file)
35 35
36local check_result = function(response, expect, ignore) 36local check_result = function(response, expect, ignore)
37 for i,v in pairs(response) do 37 for i,v in pairs(response) do
38 if not ignore[i] then 38 if not ignore[i] then
39 if v ~= expect[i] then 39 if v ~= expect[i] then
40 local f = io.open("err", "w") 40 local f = io.open("err", "w")
41 f:write(tostring(v), "\n\n versus\n\n", tostring(expect[i])) 41 f:write(tostring(v), "\n\n versus\n\n", tostring(expect[i]))
42 f:close() 42 f:close()
43 fail(i .. " differs!") 43 fail(i .. " differs!")
44 end 44 end
45 end 45 end
46 end 46 end
47 for i,v in pairs(expect) do 47 for i,v in pairs(expect) do
48 if not ignore[i] then 48 if not ignore[i] then
49 if v ~= response[i] then 49 if v ~= response[i] then
50 local f = io.open("err", "w") 50 local f = io.open("err", "w")
51 f:write(tostring(response[i]), "\n\n versus\n\n", tostring(v)) 51 f:write(tostring(response[i]), "\n\n versus\n\n", tostring(v))
52 v = string.sub(type(v) == "string" and v or "", 1, 70) 52 v = string.sub(type(v) == "string" and v or "", 1, 70)
53 f:close() 53 f:close()
54 fail(i .. " differs!") 54 fail(i .. " differs!")
55 end 55 end
56 end 56 end
57 end 57 end
58 print("ok") 58 print("ok")
59end 59end
60 60
61local check_request = function(request, expect, ignore) 61local check_request = function(request, expect, ignore)
@@ -63,7 +63,7 @@ local check_request = function(request, expect, ignore)
63 if not request.sink then request.sink, t = ltn12.sink.table() end 63 if not request.sink then request.sink, t = ltn12.sink.table() end
64 request.source = request.source or 64 request.source = request.source or
65 (request.body and ltn12.source.string(request.body)) 65 (request.body and ltn12.source.string(request.body))
66 local response = {} 66 local response = {}
67 response.code, response.headers, response.status = 67 response.code, response.headers, response.status =
68 socket.skip(1, http.request(request)) 68 socket.skip(1, http.request(request))
69 if t and table.getn(t) > 0 then response.body = table.concat(t) end 69 if t and table.getn(t) > 0 then response.body = table.concat(t) end
@@ -90,15 +90,15 @@ else fail("failed!") end
90------------------------------------------------------------------------ 90------------------------------------------------------------------------
91io.write("testing document retrieval: ") 91io.write("testing document retrieval: ")
92request = { 92request = {
93 url = "http://" .. host .. prefix .. "/index.html" 93 url = "http://" .. host .. prefix .. "/index.html"
94} 94}
95expect = { 95expect = {
96 body = index, 96 body = index,
97 code = 200 97 code = 200
98} 98}
99ignore = { 99ignore = {
100 status = 1, 100 status = 1,
101 headers = 1 101 headers = 1
102} 102}
103check_request(request, expect, ignore) 103check_request(request, expect, ignore)
104 104
@@ -111,9 +111,9 @@ expect = {
111 code = 302 111 code = 302
112} 112}
113ignore = { 113ignore = {
114 status = 1, 114 status = 1,
115 headers = 1, 115 headers = 1,
116 body = 1 116 body = 1
117} 117}
118check_request(request, expect, ignore) 118check_request(request, expect, ignore)
119 119
@@ -144,19 +144,19 @@ check_request(request, expect, ignore)
144io.write("testing post method: ") 144io.write("testing post method: ")
145-- wanted to test chunked post, but apache doesn't support it... 145-- wanted to test chunked post, but apache doesn't support it...
146request = { 146request = {
147 url = "http://" .. host .. cgiprefix .. "/cat", 147 url = "http://" .. host .. cgiprefix .. "/cat",
148 method = "POST", 148 method = "POST",
149 body = index, 149 body = index,
150 -- remove content-length header to send chunked body 150 -- remove content-length header to send chunked body
151 headers = { ["content-length"] = string.len(index) } 151 headers = { ["content-length"] = string.len(index) }
152} 152}
153expect = { 153expect = {
154 body = index, 154 body = index,
155 code = 200 155 code = 200
156} 156}
157ignore = { 157ignore = {
158 status = 1, 158 status = 1,
159 headers = 1 159 headers = 1
160} 160}
161check_request(request, expect, ignore) 161check_request(request, expect, ignore)
162 162
@@ -164,19 +164,19 @@ check_request(request, expect, ignore)
164--[[ 164--[[
165io.write("testing proxy with post method: ") 165io.write("testing proxy with post method: ")
166request = { 166request = {
167 url = "http://" .. host .. cgiprefix .. "/cat", 167 url = "http://" .. host .. cgiprefix .. "/cat",
168 method = "POST", 168 method = "POST",
169 body = index, 169 body = index,
170 headers = { ["content-length"] = string.len(index) }, 170 headers = { ["content-length"] = string.len(index) },
171 proxy= proxy 171 proxy= proxy
172} 172}
173expect = { 173expect = {
174 body = index, 174 body = index,
175 code = 200 175 code = 200
176} 176}
177ignore = { 177ignore = {
178 status = 1, 178 status = 1,
179 headers = 1 179 headers = 1
180} 180}
181check_request(request, expect, ignore) 181check_request(request, expect, ignore)
182]] 182]]
@@ -190,18 +190,18 @@ print("ok")
190------------------------------------------------------------------------ 190------------------------------------------------------------------------
191io.write("testing ltn12.(sink|source).file: ") 191io.write("testing ltn12.(sink|source).file: ")
192request = { 192request = {
193 url = "http://" .. host .. cgiprefix .. "/cat", 193 url = "http://" .. host .. cgiprefix .. "/cat",
194 method = "POST", 194 method = "POST",
195 source = ltn12.source.file(io.open(index_file, "rb")), 195 source = ltn12.source.file(io.open(index_file, "rb")),
196 sink = ltn12.sink.file(io.open(index_file .. "-back", "wb")), 196 sink = ltn12.sink.file(io.open(index_file .. "-back", "wb")),
197 headers = { ["content-length"] = string.len(index) } 197 headers = { ["content-length"] = string.len(index) }
198} 198}
199expect = { 199expect = {
200 code = 200 200 code = 200
201} 201}
202ignore = { 202ignore = {
203 status = 1, 203 status = 1,
204 headers = 1 204 headers = 1
205} 205}
206check_request(request, expect, ignore) 206check_request(request, expect, ignore)
207back = readfile(index_file .. "-back") 207back = readfile(index_file .. "-back")
@@ -231,19 +231,19 @@ local sink = ltn12.sink.chain(
231) 231)
232 232
233request = { 233request = {
234 url = "http://" .. host .. cgiprefix .. "/cat", 234 url = "http://" .. host .. cgiprefix .. "/cat",
235 method = "POST", 235 method = "POST",
236 source = source, 236 source = source,
237 sink = sink, 237 sink = sink,
238 headers = { ["content-length"] = b64length(string.len(index)) } 238 headers = { ["content-length"] = b64length(string.len(index)) }
239} 239}
240expect = { 240expect = {
241 code = 200 241 code = 200
242} 242}
243ignore = { 243ignore = {
244 body_cb = 1, 244 body_cb = 1,
245 status = 1, 245 status = 1,
246 headers = 1 246 headers = 1
247} 247}
248check_request(request, expect, ignore) 248check_request(request, expect, ignore)
249back = readfile(index_file .. "-back") 249back = readfile(index_file .. "-back")
@@ -253,15 +253,15 @@ os.remove(index_file .. "-back")
253------------------------------------------------------------------------ 253------------------------------------------------------------------------
254io.write("testing http redirection: ") 254io.write("testing http redirection: ")
255request = { 255request = {
256 url = "http://" .. host .. prefix 256 url = "http://" .. host .. prefix
257} 257}
258expect = { 258expect = {
259 body = index, 259 body = index,
260 code = 200 260 code = 200
261} 261}
262ignore = { 262ignore = {
263 status = 1, 263 status = 1,
264 headers = 1 264 headers = 1
265} 265}
266check_request(request, expect, ignore) 266check_request(request, expect, ignore)
267 267
@@ -269,16 +269,16 @@ check_request(request, expect, ignore)
269--[[ 269--[[
270io.write("testing proxy with redirection: ") 270io.write("testing proxy with redirection: ")
271request = { 271request = {
272 url = "http://" .. host .. prefix, 272 url = "http://" .. host .. prefix,
273 proxy = proxy 273 proxy = proxy
274} 274}
275expect = { 275expect = {
276 body = index, 276 body = index,
277 code = 200 277 code = 200
278} 278}
279ignore = { 279ignore = {
280 status = 1, 280 status = 1,
281 headers = 1 281 headers = 1
282} 282}
283check_request(request, expect, ignore) 283check_request(request, expect, ignore)
284]] 284]]
@@ -293,104 +293,104 @@ expect = {
293} 293}
294ignore = { 294ignore = {
295 body = 1, 295 body = 1,
296 status = 1, 296 status = 1,
297 headers = 1 297 headers = 1
298} 298}
299check_request(request, expect, ignore) 299check_request(request, expect, ignore)
300 300
301------------------------------------------------------------------------ 301------------------------------------------------------------------------
302io.write("testing http redirection failure: ") 302io.write("testing http redirection failure: ")
303request = { 303request = {
304 url = "http://" .. host .. prefix, 304 url = "http://" .. host .. prefix,
305 redirect = false 305 redirect = false
306} 306}
307expect = { 307expect = {
308 code = 301 308 code = 301
309} 309}
310ignore = { 310ignore = {
311 body = 1, 311 body = 1,
312 status = 1, 312 status = 1,
313 headers = 1 313 headers = 1
314} 314}
315check_request(request, expect, ignore) 315check_request(request, expect, ignore)
316 316
317------------------------------------------------------------------------ 317------------------------------------------------------------------------
318io.write("testing document not found: ") 318io.write("testing document not found: ")
319request = { 319request = {
320 url = "http://" .. host .. "/wrongdocument.html" 320 url = "http://" .. host .. "/wrongdocument.html"
321} 321}
322expect = { 322expect = {
323 code = 404 323 code = 404
324} 324}
325ignore = { 325ignore = {
326 body = 1, 326 body = 1,
327 status = 1, 327 status = 1,
328 headers = 1 328 headers = 1
329} 329}
330check_request(request, expect, ignore) 330check_request(request, expect, ignore)
331 331
332------------------------------------------------------------------------ 332------------------------------------------------------------------------
333io.write("testing auth failure: ") 333io.write("testing auth failure: ")
334request = { 334request = {
335 url = "http://" .. host .. prefix .. "/auth/index.html" 335 url = "http://" .. host .. prefix .. "/auth/index.html"
336} 336}
337expect = { 337expect = {
338 code = 401 338 code = 401
339} 339}
340ignore = { 340ignore = {
341 body = 1, 341 body = 1,
342 status = 1, 342 status = 1,
343 headers = 1 343 headers = 1
344} 344}
345check_request(request, expect, ignore) 345check_request(request, expect, ignore)
346 346
347------------------------------------------------------------------------ 347------------------------------------------------------------------------
348io.write("testing manual basic auth: ") 348io.write("testing manual basic auth: ")
349request = { 349request = {
350 url = "http://" .. host .. prefix .. "/auth/index.html", 350 url = "http://" .. host .. prefix .. "/auth/index.html",
351 headers = { 351 headers = {
352 authorization = "Basic " .. (mime.b64("luasocket:password")) 352 authorization = "Basic " .. (mime.b64("luasocket:password"))
353 } 353 }
354} 354}
355expect = { 355expect = {
356 code = 200, 356 code = 200,
357 body = index 357 body = index
358} 358}
359ignore = { 359ignore = {
360 status = 1, 360 status = 1,
361 headers = 1 361 headers = 1
362} 362}
363check_request(request, expect, ignore) 363check_request(request, expect, ignore)
364 364
365------------------------------------------------------------------------ 365------------------------------------------------------------------------
366io.write("testing automatic basic auth: ") 366io.write("testing automatic basic auth: ")
367request = { 367request = {
368 url = "http://luasocket:password@" .. host .. prefix .. "/auth/index.html" 368 url = "http://luasocket:password@" .. host .. prefix .. "/auth/index.html"
369} 369}
370expect = { 370expect = {
371 code = 200, 371 code = 200,
372 body = index 372 body = index
373} 373}
374ignore = { 374ignore = {
375 status = 1, 375 status = 1,
376 headers = 1 376 headers = 1
377} 377}
378check_request(request, expect, ignore) 378check_request(request, expect, ignore)
379 379
380------------------------------------------------------------------------ 380------------------------------------------------------------------------
381io.write("testing auth info overriding: ") 381io.write("testing auth info overriding: ")
382request = { 382request = {
383 url = "http://really:wrong@" .. host .. prefix .. "/auth/index.html", 383 url = "http://really:wrong@" .. host .. prefix .. "/auth/index.html",
384 user = "luasocket", 384 user = "luasocket",
385 password = "password" 385 password = "password"
386} 386}
387expect = { 387expect = {
388 code = 200, 388 code = 200,
389 body = index 389 body = index
390} 390}
391ignore = { 391ignore = {
392 status = 1, 392 status = 1,
393 headers = 1 393 headers = 1
394} 394}
395check_request(request, expect, ignore) 395check_request(request, expect, ignore)
396 396
@@ -400,12 +400,12 @@ request = {
400 url = "http://" .. host .. cgiprefix .. "/cat-index-html" 400 url = "http://" .. host .. cgiprefix .. "/cat-index-html"
401} 401}
402expect = { 402expect = {
403 body = index, 403 body = index,
404 code = 200 404 code = 200
405} 405}
406ignore = { 406ignore = {
407 status = 1, 407 status = 1,
408 headers = 1 408 headers = 1
409} 409}
410check_request(request, expect, ignore) 410check_request(request, expect, ignore)
411 411
diff --git a/test/smtptest.lua b/test/smtptest.lua
index d0c938c..5f0e0e5 100644
--- a/test/smtptest.lua
+++ b/test/smtptest.lua
@@ -19,11 +19,11 @@ local parse = mbox.parse
19dofile("testsupport.lua") 19dofile("testsupport.lua")
20 20
21local total = function() 21local total = function()
22 local t = 0 22 local t = 0
23 for i = 1, table.getn(sent) do 23 for i = 1, table.getn(sent) do
24 t = t + sent[i].count 24 t = t + sent[i].count
25 end 25 end
26 return t 26 return t
27end 27end
28 28
29local similar = function(s1, s2) 29local similar = function(s1, s2)
@@ -39,14 +39,14 @@ local fail = function(s)
39end 39end
40 40
41local readfile = function(name) 41local readfile = function(name)
42 local f = io.open(name, "r") 42 local f = io.open(name, "r")
43 if not f then 43 if not f then
44 fail("unable to open file!") 44 fail("unable to open file!")
45 return nil 45 return nil
46 end 46 end
47 local s = f:read("*a") 47 local s = f:read("*a")
48 f:close() 48 f:close()
49 return s 49 return s
50end 50end
51 51
52local empty = function() 52local empty = function()
@@ -62,7 +62,7 @@ end
62local get = function() 62local get = function()
63 local s = "" 63 local s = ""
64 for i,v in ipairs(files) do 64 for i,v in ipairs(files) do
65 s = s .. "\n" .. readfile(v) 65 s = s .. "\n" .. readfile(v)
66 end 66 end
67 return s 67 return s
68end 68end
@@ -82,40 +82,40 @@ local check_body = function(sent, got)
82end 82end
83 83
84local check = function(sent, m) 84local check = function(sent, m)
85 io.write("checking ", m.headers.title, ": ") 85 io.write("checking ", m.headers.title, ": ")
86 for i = 1, table.getn(sent) do 86 for i = 1, table.getn(sent) do
87 local s = sent[i] 87 local s = sent[i]
88 if s.title == m.headers.title and s.count > 0 then 88 if s.title == m.headers.title and s.count > 0 then
89 check_headers(s.headers, m.headers) 89 check_headers(s.headers, m.headers)
90 check_body(s.body, m.body) 90 check_body(s.body, m.body)
91 s.count = s.count - 1 91 s.count = s.count - 1
92 print("ok") 92 print("ok")
93 return 93 return
94 end 94 end
95 end 95 end
96 fail("not found") 96 fail("not found")
97end 97end
98 98
99local insert = function(sent, message) 99local insert = function(sent, message)
100 if type(message.rcpt) == "table" then 100 if type(message.rcpt) == "table" then
101 message.count = table.getn(message.rcpt) 101 message.count = table.getn(message.rcpt)
102 else message.count = 1 end 102 else message.count = 1 end
103 message.headers = message.headers or {} 103 message.headers = message.headers or {}
104 message.headers.title = message.title 104 message.headers.title = message.title
105 table.insert(sent, message) 105 table.insert(sent, message)
106end 106end
107 107
108local mark = function() 108local mark = function()
109 local time = socket.time() 109 local time = socket.time()
110 return { time = time } 110 return { time = time }
111end 111end
112 112
113local wait = function(sentinel, n) 113local wait = function(sentinel, n)
114 local to 114 local to
115 io.write("waiting for ", n, " messages: ") 115 io.write("waiting for ", n, " messages: ")
116 while 1 do 116 while 1 do
117 local mbox = parse(get()) 117 local mbox = parse(get())
118 if n == table.getn(mbox) then break end 118 if n == table.getn(mbox) then break end
119 if socket.time() - sentinel.time > 50 then 119 if socket.time() - sentinel.time > 50 then
120 to = 1 120 to = 1
121 break 121 break
@@ -124,8 +124,8 @@ local wait = function(sentinel, n)
124 io.write(".") 124 io.write(".")
125 io.stdout:flush() 125 io.stdout:flush()
126 end 126 end
127 if to then fail("timeout") 127 if to then fail("timeout")
128 else print("ok") end 128 else print("ok") end
129end 129end
130 130
131local stuffed_body = [[ 131local stuffed_body = [[
@@ -144,21 +144,21 @@ a lot of trouble.
144insert(sent, { 144insert(sent, {
145 from = from, 145 from = from,
146 rcpt = { 146 rcpt = {
147 "luasocket@localhost", 147 "luasocket@localhost",
148 "luasock3@dell-diego.cs.princeton.edu", 148 "luasock3@dell-diego.cs.princeton.edu",
149 "luasock1@dell-diego.cs.princeton.edu" 149 "luasock1@dell-diego.cs.princeton.edu"
150 }, 150 },
151 body = "multiple rcpt body", 151 body = "multiple rcpt body",
152 title = "multiple rcpt", 152 title = "multiple rcpt",
153}) 153})
154 154
155insert(sent, { 155insert(sent, {
156 from = from, 156 from = from,
157 rcpt = { 157 rcpt = {
158 "luasock2@localhost", 158 "luasock2@localhost",
159 "luasock3", 159 "luasock3",
160 "luasock1" 160 "luasock1"
161 }, 161 },
162 headers = { 162 headers = {
163 header1 = "header 1", 163 header1 = "header 1",
164 header2 = "header 2", 164 header2 = "header 2",
@@ -210,24 +210,24 @@ insert(sent, {
210io.write("testing host not found: ") 210io.write("testing host not found: ")
211local c, e = socket.connect("wrong.host", 25) 211local c, e = socket.connect("wrong.host", 25)
212local ret, err = socket.smtp.mail{ 212local ret, err = socket.smtp.mail{
213 from = from, 213 from = from,
214 rcpt = rcpt, 214 rcpt = rcpt,
215 server = "wrong.host" 215 server = "wrong.host"
216} 216}
217if ret or e ~= err then fail("wrong error message") 217if ret or e ~= err then fail("wrong error message")
218else print("ok") end 218else print("ok") end
219 219
220io.write("testing invalid from: ") 220io.write("testing invalid from: ")
221local ret, err = socket.smtp.mail{ 221local ret, err = socket.smtp.mail{
222 from = ' " " (( _ * ', 222 from = ' " " (( _ * ',
223 rcpt = rcpt, 223 rcpt = rcpt,
224} 224}
225if ret or not err then fail("wrong error message") 225if ret or not err then fail("wrong error message")
226else print(err) end 226else print(err) end
227 227
228io.write("testing no rcpt: ") 228io.write("testing no rcpt: ")
229local ret, err = socket.smtp.mail{ 229local ret, err = socket.smtp.mail{
230 from = from, 230 from = from,
231} 231}
232if ret or not err then fail("wrong error message") 232if ret or not err then fail("wrong error message")
233else print(err) end 233else print(err) end
@@ -252,7 +252,7 @@ local mbox = parse(get())
252print(table.getn(mbox) .. " messages found!") 252print(table.getn(mbox) .. " messages found!")
253 253
254for i = 1, table.getn(mbox) do 254for i = 1, table.getn(mbox) do
255 check(sent, mbox[i]) 255 check(sent, mbox[i])
256end 256end
257 257
258print("passed all tests") 258print("passed all tests")
diff --git a/test/testclnt.lua b/test/testclnt.lua
index 1f03b10..4c2f211 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -3,15 +3,20 @@ local socket = require"socket"
3host = host or "localhost" 3host = host or "localhost"
4port = port or "8383" 4port = port or "8383"
5 5
6function pass(...) 6function printf(...)
7 local s = string.format(unpack(arg)) 7 local s = string.format(unpack(arg))
8 io.stderr:write(s, "\n") 8 io.stderr:write(s)
9end
10
11function pass(...)
12 printf(...)
13 io.stderr:write("\n")
9end 14end
10 15
11function fail(...) 16function fail(...)
12 local s = string.format(unpack(arg)) 17 io.stderr:write("ERROR: ")
13 io.stderr:write("ERROR: ", s, "!\n") 18 printf(...)
14socket.sleep(3) 19 io.stderr:write("!\n")
15 os.exit() 20 os.exit()
16end 21end
17 22
@@ -80,7 +85,6 @@ io.stderr:write("----------------------------------------------\n",
80start = socket.gettime() 85start = socket.gettime()
81 86
82function reconnect() 87function reconnect()
83 io.stderr:write("attempting data connection... ")
84 if data then data:close() end 88 if data then data:close() end
85 remote [[ 89 remote [[
86 if data then data:close() data = nil end 90 if data then data:close() data = nil end
@@ -88,12 +92,11 @@ function reconnect()
88 data:setoption("tcp-nodelay", true) 92 data:setoption("tcp-nodelay", true)
89 ]] 93 ]]
90 data, err = socket.connect(host, port) 94 data, err = socket.connect(host, port)
91 if not data then fail(err) 95 if not data then fail(err) end
92 else pass("connected!") end
93 data:setoption("tcp-nodelay", true) 96 data:setoption("tcp-nodelay", true)
94end 97end
95 98
96pass("attempting control connection...") 99printf("attempting control connection...")
97control, err = socket.connect(host, port) 100control, err = socket.connect(host, port)
98if err then fail(err) 101if err then fail(err)
99else pass("connected!") end 102else pass("connected!") end
@@ -112,6 +115,7 @@ end
112------------------------------------------------------------------------ 115------------------------------------------------------------------------
113function test_mixed(len) 116function test_mixed(len)
114 reconnect() 117 reconnect()
118 io.stderr:write("length " .. len .. ": ")
115 local inter = math.ceil(len/4) 119 local inter = math.ceil(len/4)
116 local p1 = "unix " .. string.rep("x", inter) .. "line\n" 120 local p1 = "unix " .. string.rep("x", inter) .. "line\n"
117 local p2 = "dos " .. string.rep("y", inter) .. "line\r\n" 121 local p2 = "dos " .. string.rep("y", inter) .. "line\r\n"
@@ -139,6 +143,7 @@ end
139------------------------------------------------------------------------ 143------------------------------------------------------------------------
140function test_asciiline(len) 144function test_asciiline(len)
141 reconnect() 145 reconnect()
146 io.stderr:write("length " .. len .. ": ")
142 local str, str10, back, err 147 local str, str10, back, err
143 str = string.rep("x", math.mod(len, 10)) 148 str = string.rep("x", math.mod(len, 10))
144 str10 = string.rep("aZb.c#dAe?", math.floor(len/10)) 149 str10 = string.rep("aZb.c#dAe?", math.floor(len/10))
@@ -156,6 +161,7 @@ end
156------------------------------------------------------------------------ 161------------------------------------------------------------------------
157function test_rawline(len) 162function test_rawline(len)
158 reconnect() 163 reconnect()
164 io.stderr:write("length " .. len .. ": ")
159 local str, str10, back, err 165 local str, str10, back, err
160 str = string.rep(string.char(47), math.mod(len, 10)) 166 str = string.rep(string.char(47), math.mod(len, 10))
161 str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100), 167 str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100),
@@ -174,6 +180,7 @@ end
174------------------------------------------------------------------------ 180------------------------------------------------------------------------
175function test_raw(len) 181function test_raw(len)
176 reconnect() 182 reconnect()
183 io.stderr:write("length " .. len .. ": ")
177 local half = math.floor(len/2) 184 local half = math.floor(len/2)
178 local s1, s2, back, err 185 local s1, s2, back, err
179 s1 = string.rep("x", half) 186 s1 = string.rep("x", half)
@@ -194,7 +201,7 @@ end
194function test_totaltimeoutreceive(len, tm, sl) 201function test_totaltimeoutreceive(len, tm, sl)
195 reconnect() 202 reconnect()
196 local str, err, partial 203 local str, err, partial
197 pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl) 204 printf("%d bytes, %ds total timeout, %ds pause: ", len, tm, sl)
198 remote (string.format ([[ 205 remote (string.format ([[
199 data:settimeout(%d) 206 data:settimeout(%d)
200 str = string.rep('a', %d) 207 str = string.rep('a', %d)
@@ -215,7 +222,7 @@ end
215function test_totaltimeoutsend(len, tm, sl) 222function test_totaltimeoutsend(len, tm, sl)
216 reconnect() 223 reconnect()
217 local str, err, total 224 local str, err, total
218 pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl) 225 printf("%d bytes, %ds total timeout, %ds pause: ", len, tm, sl)
219 remote (string.format ([[ 226 remote (string.format ([[
220 data:settimeout(%d) 227 data:settimeout(%d)
221 str = data:receive(%d) 228 str = data:receive(%d)
@@ -235,7 +242,7 @@ end
235function test_blockingtimeoutreceive(len, tm, sl) 242function test_blockingtimeoutreceive(len, tm, sl)
236 reconnect() 243 reconnect()
237 local str, err, partial 244 local str, err, partial
238 pass("%d bytes, %ds blocking timeout, %ds pause", len, tm, sl) 245 printf("%d bytes, %ds blocking timeout, %ds pause: ", len, tm, sl)
239 remote (string.format ([[ 246 remote (string.format ([[
240 data:settimeout(%d) 247 data:settimeout(%d)
241 str = string.rep('a', %d) 248 str = string.rep('a', %d)
@@ -255,7 +262,7 @@ end
255function test_blockingtimeoutsend(len, tm, sl) 262function test_blockingtimeoutsend(len, tm, sl)
256 reconnect() 263 reconnect()
257 local str, err, total 264 local str, err, total
258 pass("%d bytes, %ds blocking timeout, %ds pause", len, tm, sl) 265 printf("%d bytes, %ds blocking timeout, %ds pause: ", len, tm, sl)
259 remote (string.format ([[ 266 remote (string.format ([[
260 data:settimeout(%d) 267 data:settimeout(%d)
261 str = data:receive(%d) 268 str = data:receive(%d)
@@ -273,6 +280,7 @@ end
273 280
274------------------------------------------------------------------------ 281------------------------------------------------------------------------
275function empty_connect() 282function empty_connect()
283 printf("empty connect: ")
276 reconnect() 284 reconnect()
277 if data then data:close() data = nil end 285 if data then data:close() data = nil end
278 remote [[ 286 remote [[
@@ -284,7 +292,7 @@ function empty_connect()
284 pass("ok") 292 pass("ok")
285 data = socket.connect(host, port) 293 data = socket.connect(host, port)
286 else 294 else
287 pass("gethostbyname returns localhost on empty string...") 295 pass("gethostbyname returns localhost on empty string...")
288 end 296 end
289end 297end
290 298
@@ -311,7 +319,7 @@ function test_closed()
311 local back, partial, err 319 local back, partial, err
312 local str = 'little string' 320 local str = 'little string'
313 reconnect() 321 reconnect()
314 pass("trying read detection") 322 printf("trying read detection: ")
315 remote (string.format ([[ 323 remote (string.format ([[
316 data:send('%s') 324 data:send('%s')
317 data:close() 325 data:close()
@@ -324,7 +332,7 @@ function test_closed()
324 elseif str ~= partial then fail("didn't receive partial result.") 332 elseif str ~= partial then fail("didn't receive partial result.")
325 else pass("graceful 'closed' received") end 333 else pass("graceful 'closed' received") end
326 reconnect() 334 reconnect()
327 pass("trying write detection") 335 printf("trying write detection: ")
328 remote [[ 336 remote [[
329 data:close() 337 data:close()
330 data = nil 338 data = nil
@@ -342,7 +350,6 @@ end
342------------------------------------------------------------------------ 350------------------------------------------------------------------------
343function test_selectbugs() 351function test_selectbugs()
344 local r, s, e = socket.select(nil, nil, 0.1) 352 local r, s, e = socket.select(nil, nil, 0.1)
345print(r, s, e)
346 assert(type(r) == "table" and type(s) == "table" and 353 assert(type(r) == "table" and type(s) == "table" and
347 (e == "timeout" or e == "error")) 354 (e == "timeout" or e == "error"))
348 pass("both nil: ok") 355 pass("both nil: ok")
@@ -374,7 +381,7 @@ end
374 381
375------------------------------------------------------------------------ 382------------------------------------------------------------------------
376function accept_timeout() 383function accept_timeout()
377 io.stderr:write("accept with timeout (if it hangs, it failed): ") 384 printf("accept with timeout (if it hangs, it failed): ")
378 local s, e = socket.bind("*", 0, 0) 385 local s, e = socket.bind("*", 0, 0)
379 assert(s, e) 386 assert(s, e)
380 local t = socket.gettime() 387 local t = socket.gettime()
@@ -390,23 +397,22 @@ end
390 397
391------------------------------------------------------------------------ 398------------------------------------------------------------------------
392function connect_timeout() 399function connect_timeout()
393 io.stderr:write("connect with timeout (if it hangs, it failed!): ") 400 printf("connect with timeout (if it hangs, it failed!): ")
394 local t = socket.gettime() 401 local t = socket.gettime()
395 local c, e = socket.tcp() 402 local c, e = socket.tcp()
396 assert(c, e) 403 assert(c, e)
397 c:settimeout(0.1) 404 c:settimeout(0.1)
398 local t = socket.gettime() 405 local t = socket.gettime()
399 local r, e = c:connect("10.0.0.1", 81) 406 local r, e = c:connect("10.0.0.1", 81)
400print(r, e)
401 assert(not r, "should not connect") 407 assert(not r, "should not connect")
402 assert(socket.gettime() - t < 2, "took too long to give up.") 408 assert(socket.gettime() - t < 2, "took too long to give up.")
403 c:close() 409 c:close()
404 print("ok") 410 pass("ok")
405end 411end
406 412
407------------------------------------------------------------------------ 413------------------------------------------------------------------------
408function accept_errors() 414function accept_errors()
409 io.stderr:write("not listening: ") 415 printf("not listening: ")
410 local d, e = socket.bind("*", 0) 416 local d, e = socket.bind("*", 0)
411 assert(d, e); 417 assert(d, e);
412 local c, e = socket.tcp(); 418 local c, e = socket.tcp();
@@ -415,26 +421,26 @@ function accept_errors()
415 d:settimeout(2) 421 d:settimeout(2)
416 local r, e = d:accept() 422 local r, e = d:accept()
417 assert(not r and e) 423 assert(not r and e)
418 print("ok: ", e) 424 pass("ok")
419 io.stderr:write("not supported: ") 425 printf("not supported: ")
420 local c, e = socket.udp() 426 local c, e = socket.udp()
421 assert(c, e); 427 assert(c, e);
422 d:setfd(c:getfd()) 428 d:setfd(c:getfd())
423 local r, e = d:accept() 429 local r, e = d:accept()
424 assert(not r and e) 430 assert(not r and e)
425 print("ok: ", e) 431 pass("ok")
426end 432end
427 433
428------------------------------------------------------------------------ 434------------------------------------------------------------------------
429function connect_errors() 435function connect_errors()
430 io.stderr:write("connection refused: ") 436 printf("connection refused: ")
431 local c, e = socket.connect("localhost", 1); 437 local c, e = socket.connect("localhost", 1);
432 assert(not c and e) 438 assert(not c and e)
433 print("ok: ", e) 439 pass("ok")
434 io.stderr:write("host not found: ") 440 printf("host not found: ")
435 local c, e = socket.connect("host.is.invalid", 1); 441 local c, e = socket.connect("host.is.invalid", 1);
436 assert(not c and e, e) 442 assert(not c and e, e)
437 print("ok: ", e) 443 pass("ok")
438end 444end
439 445
440------------------------------------------------------------------------ 446------------------------------------------------------------------------
@@ -447,7 +453,7 @@ function rebind_test()
447 r, e = s:bind("localhost", p) 453 r, e = s:bind("localhost", p)
448 assert(not r, "managed to rebind!") 454 assert(not r, "managed to rebind!")
449 assert(e) 455 assert(e)
450 print("ok: ", e) 456 pass("ok")
451end 457end
452 458
453------------------------------------------------------------------------ 459------------------------------------------------------------------------
@@ -469,14 +475,14 @@ function getstats_test()
469 assert(s == t, "sent count failed" .. tostring(s) 475 assert(s == t, "sent count failed" .. tostring(s)
470 .. "/" .. tostring(t)) 476 .. "/" .. tostring(t))
471 end 477 end
472 print("ok") 478 pass("ok")
473end 479end
474 480
475 481
476------------------------------------------------------------------------ 482------------------------------------------------------------------------
477function test_nonblocking(size) 483function test_nonblocking(size)
478 reconnect() 484 reconnect()
479print("Testing " .. 2*size .. " bytes") 485 printf("testing " .. 2*size .. " bytes: ")
480remote(string.format([[ 486remote(string.format([[
481 data:send(string.rep("a", %d)) 487 data:send(string.rep("a", %d))
482 socket.sleep(0.5) 488 socket.sleep(0.5)
@@ -508,7 +514,7 @@ remote(string.format([[
508 data:settimeout(-1) 514 data:settimeout(-1)
509 local back = data:receive(2*size) 515 local back = data:receive(2*size)
510 assert(back == str, "'" .. back .. "' vs '" .. str .. "'") 516 assert(back == str, "'" .. back .. "' vs '" .. str .. "'")
511 print("ok") 517 pass("ok")
512end 518end
513 519
514------------------------------------------------------------------------ 520------------------------------------------------------------------------
@@ -516,7 +522,7 @@ function test_readafterclose()
516 local back, partial, err 522 local back, partial, err
517 local str = 'little string' 523 local str = 'little string'
518 reconnect() 524 reconnect()
519 pass("trying repeated '*a' pattern") 525 printf("trying repeated '*a' pattern")
520 remote (string.format ([[ 526 remote (string.format ([[
521 data:send('%s') 527 data:send('%s')
522 data:close() 528 data:close()
@@ -526,9 +532,9 @@ function test_readafterclose()
526 assert(back == str, "unexpected data read") 532 assert(back == str, "unexpected data read")
527 back, err, partial = data:receive("*a") 533 back, err, partial = data:receive("*a")
528 assert(back == nil and err == "closed", "should have returned 'closed'") 534 assert(back == nil and err == "closed", "should have returned 'closed'")
529 print("ok") 535 pass("ok")
530 reconnect() 536 reconnect()
531 pass("trying active close before '*a'") 537 printf("trying active close before '*a'")
532 remote (string.format ([[ 538 remote (string.format ([[
533 data:close() 539 data:close()
534 data = nil 540 data = nil
@@ -536,9 +542,9 @@ function test_readafterclose()
536 data:close() 542 data:close()
537 back, err, partial = data:receive("*a") 543 back, err, partial = data:receive("*a")
538 assert(back == nil and err == "closed", "should have returned 'closed'") 544 assert(back == nil and err == "closed", "should have returned 'closed'")
539 print("ok") 545 pass("ok")
540 reconnect() 546 reconnect()
541 pass("trying active close before '*l'") 547 printf("trying active close before '*l'")
542 remote (string.format ([[ 548 remote (string.format ([[
543 data:close() 549 data:close()
544 data = nil 550 data = nil
@@ -546,9 +552,9 @@ function test_readafterclose()
546 data:close() 552 data:close()
547 back, err, partial = data:receive() 553 back, err, partial = data:receive()
548 assert(back == nil and err == "closed", "should have returned 'closed'") 554 assert(back == nil and err == "closed", "should have returned 'closed'")
549 print("ok") 555 pass("ok")
550 reconnect() 556 reconnect()
551 pass("trying active close before raw 1") 557 printf("trying active close before raw 1")
552 remote (string.format ([[ 558 remote (string.format ([[
553 data:close() 559 data:close()
554 data = nil 560 data = nil
@@ -556,9 +562,9 @@ function test_readafterclose()
556 data:close() 562 data:close()
557 back, err, partial = data:receive(1) 563 back, err, partial = data:receive(1)
558 assert(back == nil and err == "closed", "should have returned 'closed'") 564 assert(back == nil and err == "closed", "should have returned 'closed'")
559 print("ok") 565 pass("ok")
560 reconnect() 566 reconnect()
561 pass("trying active close before raw 0") 567 printf("trying active close before raw 0")
562 remote (string.format ([[ 568 remote (string.format ([[
563 data:close() 569 data:close()
564 data = nil 570 data = nil
@@ -566,7 +572,7 @@ function test_readafterclose()
566 data:close() 572 data:close()
567 back, err, partial = data:receive(0) 573 back, err, partial = data:receive(0)
568 assert(back == nil and err == "closed", "should have returned 'closed'") 574 assert(back == nil and err == "closed", "should have returned 'closed'")
569 print("ok") 575 pass("ok")
570end 576end
571 577
572------------------------------------------------------------------------ 578------------------------------------------------------------------------
@@ -581,13 +587,29 @@ function test_writeafterclose()
581 while not err do 587 while not err do
582 sent, err, errsent, time = data:send(str) 588 sent, err, errsent, time = data:send(str)
583 end 589 end
584 print(sent, err, errsent, time) 590 assert(err == "closed", "should have returned 'closed'")
585 print("ok") 591 pass("ok")
586end 592end
587 593
588------------------------------------------------------------------------ 594------------------------------------------------------------------------
589--test_writeafterclose()
590 595
596function test_partialrecv()
597 local str = 'little string'
598 reconnect()
599remote([[
600 data:send("7890")
601]])
602 data:settimeout(1)
603 back, err = data:receive(10, "123456")
604 assert(back == "1234567890", "failed on exact mixed length")
605 back, err = data:receive(8, "87654321")
606 assert(back == "87654321", "failed on exact length")
607 back, err = data:receive(4, "87654321")
608 assert(back == "87654321", "failed on smaller length")
609 pass("ok")
610end
611
612------------------------------------------------------------------------
591test("method registration") 613test("method registration")
592test_methods(socket.tcp(), { 614test_methods(socket.tcp(), {
593 "accept", 615 "accept",
@@ -629,12 +651,18 @@ test_methods(socket.udp(), {
629 "settimeout" 651 "settimeout"
630}) 652})
631 653
654test("partial receive")
655test_partialrecv()
656
632test("select function") 657test("select function")
633test_selectbugs() 658test_selectbugs()
634 659
635test("testing read after close") 660test("read after close")
636test_readafterclose() 661test_readafterclose()
637 662
663test("write after close")
664test_writeafterclose()
665
638test("connect function") 666test("connect function")
639connect_timeout() 667connect_timeout()
640empty_connect() 668empty_connect()
diff --git a/test/testsupport.lua b/test/testsupport.lua
index acad8f5..b986088 100644
--- a/test/testsupport.lua
+++ b/test/testsupport.lua
@@ -1,13 +1,13 @@
1function readfile(name) 1function readfile(name)
2 local f = io.open(name, "rb") 2 local f = io.open(name, "rb")
3 if not f then return nil end 3 if not f then return nil end
4 local s = f:read("*a") 4 local s = f:read("*a")
5 f:close() 5 f:close()
6 return s 6 return s
7end 7end
8 8
9function similar(s1, s2) 9function similar(s1, s2)
10 return string.lower(string.gsub(s1 or "", "%s", "")) == 10 return string.lower(string.gsub(s1 or "", "%s", "")) ==
11 string.lower(string.gsub(s2 or "", "%s", "")) 11 string.lower(string.gsub(s2 or "", "%s", ""))
12end 12end
13 13
@@ -28,7 +28,7 @@ local set = rawset
28local warn = print 28local warn = print
29 29
30local setglobal = function(table, key, value) 30local setglobal = function(table, key, value)
31 warn("changed " .. key) 31 warn("changed " .. key)
32 set(table, key, value) 32 set(table, key, value)
33end 33end
34 34
diff --git a/test/urltest.lua b/test/urltest.lua
index 8dc0c14..d46cb03 100644
--- a/test/urltest.lua
+++ b/test/urltest.lua
@@ -3,439 +3,439 @@ socket.url = require("socket.url")
3dofile("testsupport.lua") 3dofile("testsupport.lua")
4 4
5local check_build_url = function(parsed) 5local check_build_url = function(parsed)
6 local built = socket.url.build(parsed) 6 local built = socket.url.build(parsed)
7 if built ~= parsed.url then 7 if built ~= parsed.url then
8 print("built is different from expected") 8 print("built is different from expected")
9 print(built) 9 print(built)
10 print(expected) 10 print(expected)
11 exit() 11 exit()
12 end 12 end
13end 13end
14 14
15local check_protect = function(parsed, path, unsafe) 15local check_protect = function(parsed, path, unsafe)
16 local built = socket.url.build_path(parsed, unsafe) 16 local built = socket.url.build_path(parsed, unsafe)
17 if built ~= path then 17 if built ~= path then
18 print(built, path) 18 print(built, path)
19 print("path composition failed.") 19 print("path composition failed.")
20 exit() 20 exit()
21 end 21 end
22end 22end
23 23
24local check_invert = function(url) 24local check_invert = function(url)
25 local parsed = socket.url.parse(url) 25 local parsed = socket.url.parse(url)
26 parsed.path = socket.url.build_path(socket.url.parse_path(parsed.path)) 26 parsed.path = socket.url.build_path(socket.url.parse_path(parsed.path))
27 local rebuilt = socket.url.build(parsed) 27 local rebuilt = socket.url.build(parsed)
28 if rebuilt ~= url then 28 if rebuilt ~= url then
29 print(url, rebuilt) 29 print(url, rebuilt)
30 print("original and rebuilt are different") 30 print("original and rebuilt are different")
31 exit() 31 exit()
32 end 32 end
33end 33end
34 34
35local check_parse_path = function(path, expect) 35local check_parse_path = function(path, expect)
36 local parsed = socket.url.parse_path(path) 36 local parsed = socket.url.parse_path(path)
37 for i = 1, math.max(table.getn(parsed), table.getn(expect)) do 37 for i = 1, math.max(table.getn(parsed), table.getn(expect)) do
38 if parsed[i] ~= expect[i] then 38 if parsed[i] ~= expect[i] then
39 print(path) 39 print(path)
40 exit() 40 exit()
41 end 41 end
42 end 42 end
43 if expect.is_directory ~= parsed.is_directory then 43 if expect.is_directory ~= parsed.is_directory then
44 print(path) 44 print(path)
45 print("is_directory mismatch") 45 print("is_directory mismatch")
46 exit() 46 exit()
47 end 47 end
48 if expect.is_absolute ~= parsed.is_absolute then 48 if expect.is_absolute ~= parsed.is_absolute then
49 print(path) 49 print(path)
50 print("is_absolute mismatch") 50 print("is_absolute mismatch")
51 exit() 51 exit()
52 end 52 end
53 local built = socket.url.build_path(expect) 53 local built = socket.url.build_path(expect)
54 if built ~= path then 54 if built ~= path then
55 print(built, path) 55 print(built, path)
56 print("path composition failed.") 56 print("path composition failed.")
57 exit() 57 exit()
58 end 58 end
59end 59end
60 60
61local check_absolute_url = function(base, relative, absolute) 61local check_absolute_url = function(base, relative, absolute)
62 local res = socket.url.absolute(base, relative) 62 local res = socket.url.absolute(base, relative)
63 if res ~= absolute then 63 if res ~= absolute then
64 io.write("absolute: In test for '", relative, "' expected '", 64 io.write("absolute: In test for '", relative, "' expected '",
65 absolute, "' but got '", res, "'\n") 65 absolute, "' but got '", res, "'\n")
66 exit() 66 exit()
67 end 67 end
68end 68end
69 69
70local check_parse_url = function(gaba) 70local check_parse_url = function(gaba)
71 local url = gaba.url 71 local url = gaba.url
72 gaba.url = nil 72 gaba.url = nil
73 local parsed = socket.url.parse(url) 73 local parsed = socket.url.parse(url)
74 for i, v in pairs(gaba) do 74 for i, v in pairs(gaba) do
75 if v ~= parsed[i] then 75 if v ~= parsed[i] then
76 io.write("parse: In test for '", url, "' expected ", i, " = '", 76 io.write("parse: In test for '", url, "' expected ", i, " = '",
77 v, "' but got '", tostring(parsed[i]), "'\n") 77 v, "' but got '", tostring(parsed[i]), "'\n")
78 for i,v in pairs(parsed) do print(i,v) end 78 for i,v in pairs(parsed) do print(i,v) end
79 exit() 79 exit()
80 end 80 end
81 end 81 end
82 for i, v in pairs(parsed) do 82 for i, v in pairs(parsed) do
83 if v ~= gaba[i] then 83 if v ~= gaba[i] then
84 io.write("parse: In test for '", url, "' expected ", i, " = '", 84 io.write("parse: In test for '", url, "' expected ", i, " = '",
85 tostring(gaba[i]), "' but got '", v, "'\n") 85 tostring(gaba[i]), "' but got '", v, "'\n")
86 for i,v in pairs(parsed) do print(i,v) end 86 for i,v in pairs(parsed) do print(i,v) end
87 exit() 87 exit()
88 end 88 end
89 end 89 end
90end 90end
91 91
92print("testing URL parsing") 92print("testing URL parsing")
93check_parse_url{ 93check_parse_url{
94 url = "scheme://userinfo@host:port/path;params?query#fragment", 94 url = "scheme://userinfo@host:port/path;params?query#fragment",
95 scheme = "scheme", 95 scheme = "scheme",
96 authority = "userinfo@host:port", 96 authority = "userinfo@host:port",
97 host = "host", 97 host = "host",
98 port = "port", 98 port = "port",
99 userinfo = "userinfo", 99 userinfo = "userinfo",
100 user = "userinfo", 100 user = "userinfo",
101 path = "/path", 101 path = "/path",
102 params = "params", 102 params = "params",
103 query = "query", 103 query = "query",
104 fragment = "fragment" 104 fragment = "fragment"
105} 105}
106 106
107check_parse_url{ 107check_parse_url{
108 url = "scheme://user:password@host:port/path;params?query#fragment", 108 url = "scheme://user:password@host:port/path;params?query#fragment",
109 scheme = "scheme", 109 scheme = "scheme",
110 authority = "user:password@host:port", 110 authority = "user:password@host:port",
111 host = "host", 111 host = "host",
112 port = "port", 112 port = "port",
113 userinfo = "user:password", 113 userinfo = "user:password",
114 user = "user", 114 user = "user",
115 password = "password", 115 password = "password",
116 path = "/path", 116 path = "/path",
117 params = "params", 117 params = "params",
118 query = "query", 118 query = "query",
119 fragment = "fragment", 119 fragment = "fragment",
120} 120}
121 121
122check_parse_url{ 122check_parse_url{
123 url = "scheme://userinfo@host:port/path;params?query#", 123 url = "scheme://userinfo@host:port/path;params?query#",
124 scheme = "scheme", 124 scheme = "scheme",
125 authority = "userinfo@host:port", 125 authority = "userinfo@host:port",
126 host = "host", 126 host = "host",
127 port = "port", 127 port = "port",
128 userinfo = "userinfo", 128 userinfo = "userinfo",
129 user = "userinfo", 129 user = "userinfo",
130 path = "/path", 130 path = "/path",
131 params = "params", 131 params = "params",
132 query = "query", 132 query = "query",
133 fragment = "" 133 fragment = ""
134} 134}
135 135
136check_parse_url{ 136check_parse_url{
137 url = "scheme://userinfo@host:port/path;params?#fragment", 137 url = "scheme://userinfo@host:port/path;params?#fragment",
138 scheme = "scheme", 138 scheme = "scheme",
139 authority = "userinfo@host:port", 139 authority = "userinfo@host:port",
140 host = "host", 140 host = "host",
141 port = "port", 141 port = "port",
142 userinfo = "userinfo", 142 userinfo = "userinfo",
143 user = "userinfo", 143 user = "userinfo",
144 path = "/path", 144 path = "/path",
145 params = "params", 145 params = "params",
146 query = "", 146 query = "",
147 fragment = "fragment" 147 fragment = "fragment"
148} 148}
149 149
150check_parse_url{ 150check_parse_url{
151 url = "scheme://userinfo@host:port/path;params#fragment", 151 url = "scheme://userinfo@host:port/path;params#fragment",
152 scheme = "scheme", 152 scheme = "scheme",
153 authority = "userinfo@host:port", 153 authority = "userinfo@host:port",
154 host = "host", 154 host = "host",
155 port = "port", 155 port = "port",
156 userinfo = "userinfo", 156 userinfo = "userinfo",
157 user = "userinfo", 157 user = "userinfo",
158 path = "/path", 158 path = "/path",
159 params = "params", 159 params = "params",
160 fragment = "fragment" 160 fragment = "fragment"
161} 161}
162 162
163check_parse_url{ 163check_parse_url{
164 url = "scheme://userinfo@host:port/path;?query#fragment", 164 url = "scheme://userinfo@host:port/path;?query#fragment",
165 scheme = "scheme", 165 scheme = "scheme",
166 authority = "userinfo@host:port", 166 authority = "userinfo@host:port",
167 host = "host", 167 host = "host",
168 port = "port", 168 port = "port",
169 userinfo = "userinfo", 169 userinfo = "userinfo",
170 user = "userinfo", 170 user = "userinfo",
171 path = "/path", 171 path = "/path",
172 params = "", 172 params = "",
173 query = "query", 173 query = "query",
174 fragment = "fragment" 174 fragment = "fragment"
175} 175}
176 176
177check_parse_url{ 177check_parse_url{
178 url = "scheme://userinfo@host:port/path?query#fragment", 178 url = "scheme://userinfo@host:port/path?query#fragment",
179 scheme = "scheme", 179 scheme = "scheme",
180 authority = "userinfo@host:port", 180 authority = "userinfo@host:port",
181 host = "host", 181 host = "host",
182 port = "port", 182 port = "port",
183 userinfo = "userinfo", 183 userinfo = "userinfo",
184 user = "userinfo", 184 user = "userinfo",
185 path = "/path", 185 path = "/path",
186 query = "query", 186 query = "query",
187 fragment = "fragment" 187 fragment = "fragment"
188} 188}
189 189
190check_parse_url{ 190check_parse_url{
191 url = "scheme://userinfo@host:port/;params?query#fragment", 191 url = "scheme://userinfo@host:port/;params?query#fragment",
192 scheme = "scheme", 192 scheme = "scheme",
193 authority = "userinfo@host:port", 193 authority = "userinfo@host:port",
194 host = "host", 194 host = "host",
195 port = "port", 195 port = "port",
196 userinfo = "userinfo", 196 userinfo = "userinfo",
197 user = "userinfo", 197 user = "userinfo",
198 path = "/", 198 path = "/",
199 params = "params", 199 params = "params",
200 query = "query", 200 query = "query",
201 fragment = "fragment" 201 fragment = "fragment"
202} 202}
203 203
204check_parse_url{ 204check_parse_url{
205 url = "scheme://userinfo@host:port", 205 url = "scheme://userinfo@host:port",
206 scheme = "scheme", 206 scheme = "scheme",
207 authority = "userinfo@host:port", 207 authority = "userinfo@host:port",
208 host = "host", 208 host = "host",
209 port = "port", 209 port = "port",
210 userinfo = "userinfo", 210 userinfo = "userinfo",
211 user = "userinfo", 211 user = "userinfo",
212} 212}
213 213
214check_parse_url{ 214check_parse_url{
215 url = "//userinfo@host:port/path;params?query#fragment", 215 url = "//userinfo@host:port/path;params?query#fragment",
216 authority = "userinfo@host:port", 216 authority = "userinfo@host:port",
217 host = "host", 217 host = "host",
218 port = "port", 218 port = "port",
219 userinfo = "userinfo", 219 userinfo = "userinfo",
220 user = "userinfo", 220 user = "userinfo",
221 path = "/path", 221 path = "/path",
222 params = "params", 222 params = "params",
223 query = "query", 223 query = "query",
224 fragment = "fragment" 224 fragment = "fragment"
225} 225}
226 226
227check_parse_url{ 227check_parse_url{
228 url = "//userinfo@host:port/path", 228 url = "//userinfo@host:port/path",
229 authority = "userinfo@host:port", 229 authority = "userinfo@host:port",
230 host = "host", 230 host = "host",
231 port = "port", 231 port = "port",
232 userinfo = "userinfo", 232 userinfo = "userinfo",
233 user = "userinfo", 233 user = "userinfo",
234 path = "/path", 234 path = "/path",
235} 235}
236 236
237check_parse_url{ 237check_parse_url{
238 url = "//userinfo@host/path", 238 url = "//userinfo@host/path",
239 authority = "userinfo@host", 239 authority = "userinfo@host",
240 host = "host", 240 host = "host",
241 userinfo = "userinfo", 241 userinfo = "userinfo",
242 user = "userinfo", 242 user = "userinfo",
243 path = "/path", 243 path = "/path",
244} 244}
245 245
246check_parse_url{ 246check_parse_url{
247 url = "//user:password@host/path", 247 url = "//user:password@host/path",
248 authority = "user:password@host", 248 authority = "user:password@host",
249 host = "host", 249 host = "host",
250 userinfo = "user:password", 250 userinfo = "user:password",
251 password = "password", 251 password = "password",
252 user = "user", 252 user = "user",
253 path = "/path", 253 path = "/path",
254} 254}
255 255
256check_parse_url{ 256check_parse_url{
257 url = "//user:@host/path", 257 url = "//user:@host/path",
258 authority = "user:@host", 258 authority = "user:@host",
259 host = "host", 259 host = "host",
260 userinfo = "user:", 260 userinfo = "user:",
261 password = "", 261 password = "",
262 user = "user", 262 user = "user",
263 path = "/path", 263 path = "/path",
264} 264}
265 265
266check_parse_url{ 266check_parse_url{
267 url = "//user@host:port/path", 267 url = "//user@host:port/path",
268 authority = "user@host:port", 268 authority = "user@host:port",
269 host = "host", 269 host = "host",
270 userinfo = "user", 270 userinfo = "user",
271 user = "user", 271 user = "user",
272 port = "port", 272 port = "port",
273 path = "/path", 273 path = "/path",
274} 274}
275 275
276check_parse_url{ 276check_parse_url{
277 url = "//host:port/path", 277 url = "//host:port/path",
278 authority = "host:port", 278 authority = "host:port",
279 port = "port", 279 port = "port",
280 host = "host", 280 host = "host",
281 path = "/path", 281 path = "/path",
282} 282}
283 283
284check_parse_url{ 284check_parse_url{
285 url = "//host/path", 285 url = "//host/path",
286 authority = "host", 286 authority = "host",
287 host = "host", 287 host = "host",
288 path = "/path", 288 path = "/path",
289} 289}
290 290
291check_parse_url{ 291check_parse_url{
292 url = "//host", 292 url = "//host",
293 authority = "host", 293 authority = "host",
294 host = "host", 294 host = "host",
295} 295}
296 296
297check_parse_url{ 297check_parse_url{
298 url = "/path", 298 url = "/path",
299 path = "/path", 299 path = "/path",
300} 300}
301 301
302check_parse_url{ 302check_parse_url{
303 url = "path", 303 url = "path",
304 path = "path", 304 path = "path",
305} 305}
306 306
307print("testing URL building") 307print("testing URL building")
308check_build_url { 308check_build_url {
309 url = "scheme://user:password@host:port/path;params?query#fragment", 309 url = "scheme://user:password@host:port/path;params?query#fragment",
310 scheme = "scheme", 310 scheme = "scheme",
311 host = "host", 311 host = "host",
312 port = "port", 312 port = "port",
313 user = "user", 313 user = "user",
314 password = "password", 314 password = "password",
315 path = "/path", 315 path = "/path",
316 params = "params", 316 params = "params",
317 query = "query", 317 query = "query",
318 fragment = "fragment" 318 fragment = "fragment"
319} 319}
320 320
321check_build_url { 321check_build_url {
322 url = "scheme://user:password@host/path;params?query#fragment", 322 url = "scheme://user:password@host/path;params?query#fragment",
323 scheme = "scheme", 323 scheme = "scheme",
324 host = "host", 324 host = "host",
325 user = "user", 325 user = "user",
326 password = "password", 326 password = "password",
327 path = "/path", 327 path = "/path",
328 params = "params", 328 params = "params",
329 query = "query", 329 query = "query",
330 fragment = "fragment" 330 fragment = "fragment"
331} 331}
332 332
333check_build_url { 333check_build_url {
334 url = "scheme://user@host/path;params?query#fragment", 334 url = "scheme://user@host/path;params?query#fragment",
335 scheme = "scheme", 335 scheme = "scheme",
336 host = "host", 336 host = "host",
337 user = "user", 337 user = "user",
338 path = "/path", 338 path = "/path",
339 params = "params", 339 params = "params",
340 query = "query", 340 query = "query",
341 fragment = "fragment" 341 fragment = "fragment"
342} 342}
343 343
344check_build_url { 344check_build_url {
345 url = "scheme://host/path;params?query#fragment", 345 url = "scheme://host/path;params?query#fragment",
346 scheme = "scheme", 346 scheme = "scheme",
347 host = "host", 347 host = "host",
348 path = "/path", 348 path = "/path",
349 params = "params", 349 params = "params",
350 query = "query", 350 query = "query",
351 fragment = "fragment" 351 fragment = "fragment"
352} 352}
353 353
354check_build_url { 354check_build_url {
355 url = "scheme://host/path;params#fragment", 355 url = "scheme://host/path;params#fragment",
356 scheme = "scheme", 356 scheme = "scheme",
357 host = "host", 357 host = "host",
358 path = "/path", 358 path = "/path",
359 params = "params", 359 params = "params",
360 fragment = "fragment" 360 fragment = "fragment"
361} 361}
362 362
363check_build_url { 363check_build_url {
364 url = "scheme://host/path#fragment", 364 url = "scheme://host/path#fragment",
365 scheme = "scheme", 365 scheme = "scheme",
366 host = "host", 366 host = "host",
367 path = "/path", 367 path = "/path",
368 fragment = "fragment" 368 fragment = "fragment"
369} 369}
370 370
371check_build_url { 371check_build_url {
372 url = "scheme://host/path", 372 url = "scheme://host/path",
373 scheme = "scheme", 373 scheme = "scheme",
374 host = "host", 374 host = "host",
375 path = "/path", 375 path = "/path",
376} 376}
377 377
378check_build_url { 378check_build_url {
379 url = "//host/path", 379 url = "//host/path",
380 host = "host", 380 host = "host",
381 path = "/path", 381 path = "/path",
382} 382}
383 383
384check_build_url { 384check_build_url {
385 url = "/path", 385 url = "/path",
386 path = "/path", 386 path = "/path",
387} 387}
388 388
389check_build_url { 389check_build_url {
390 url = "scheme://user:password@host:port/path;params?query#fragment", 390 url = "scheme://user:password@host:port/path;params?query#fragment",
391 scheme = "scheme", 391 scheme = "scheme",
392 host = "host", 392 host = "host",
393 port = "port", 393 port = "port",
394 user = "user", 394 user = "user",
395 userinfo = "not used", 395 userinfo = "not used",
396 password = "password", 396 password = "password",
397 path = "/path", 397 path = "/path",
398 params = "params", 398 params = "params",
399 query = "query", 399 query = "query",
400 fragment = "fragment" 400 fragment = "fragment"
401} 401}
402 402
403check_build_url { 403check_build_url {
404 url = "scheme://user:password@host:port/path;params?query#fragment", 404 url = "scheme://user:password@host:port/path;params?query#fragment",
405 scheme = "scheme", 405 scheme = "scheme",
406 host = "host", 406 host = "host",
407 port = "port", 407 port = "port",
408 user = "user", 408 user = "user",
409 userinfo = "not used", 409 userinfo = "not used",
410 authority = "not used", 410 authority = "not used",
411 password = "password", 411 password = "password",
412 path = "/path", 412 path = "/path",
413 params = "params", 413 params = "params",
414 query = "query", 414 query = "query",
415 fragment = "fragment" 415 fragment = "fragment"
416} 416}
417 417
418check_build_url { 418check_build_url {
419 url = "scheme://user:password@host:port/path;params?query#fragment", 419 url = "scheme://user:password@host:port/path;params?query#fragment",
420 scheme = "scheme", 420 scheme = "scheme",
421 host = "host", 421 host = "host",
422 port = "port", 422 port = "port",
423 userinfo = "user:password", 423 userinfo = "user:password",
424 authority = "not used", 424 authority = "not used",
425 path = "/path", 425 path = "/path",
426 params = "params", 426 params = "params",
427 query = "query", 427 query = "query",
428 fragment = "fragment" 428 fragment = "fragment"
429} 429}
430 430
431check_build_url { 431check_build_url {
432 url = "scheme://user:password@host:port/path;params?query#fragment", 432 url = "scheme://user:password@host:port/path;params?query#fragment",
433 scheme = "scheme", 433 scheme = "scheme",
434 authority = "user:password@host:port", 434 authority = "user:password@host:port",
435 path = "/path", 435 path = "/path",
436 params = "params", 436 params = "params",
437 query = "query", 437 query = "query",
438 fragment = "fragment" 438 fragment = "fragment"
439} 439}
440 440
441-- standard RFC tests 441-- standard RFC tests
@@ -488,11 +488,11 @@ print("testing path parsing and composition")
488check_parse_path("/eu/tu/ele", { "eu", "tu", "ele"; is_absolute = 1 }) 488check_parse_path("/eu/tu/ele", { "eu", "tu", "ele"; is_absolute = 1 })
489check_parse_path("/eu/", { "eu"; is_absolute = 1, is_directory = 1 }) 489check_parse_path("/eu/", { "eu"; is_absolute = 1, is_directory = 1 })
490check_parse_path("eu/tu/ele/nos/vos/eles/", 490check_parse_path("eu/tu/ele/nos/vos/eles/",
491 { "eu", "tu", "ele", "nos", "vos", "eles"; is_directory = 1}) 491 { "eu", "tu", "ele", "nos", "vos", "eles"; is_directory = 1})
492check_parse_path("/", { is_absolute = 1, is_directory = 1}) 492check_parse_path("/", { is_absolute = 1, is_directory = 1})
493check_parse_path("", { }) 493check_parse_path("", { })
494check_parse_path("eu%01/%02tu/e%03l%04e/nos/vos%05/e%12les/", 494check_parse_path("eu%01/%02tu/e%03l%04e/nos/vos%05/e%12les/",
495 { "eu\1", "\2tu", "e\3l\4e", "nos", "vos\5", "e\18les"; is_directory = 1}) 495 { "eu\1", "\2tu", "e\3l\4e", "nos", "vos\5", "e\18les"; is_directory = 1})
496check_parse_path("eu/tu", { "eu", "tu" }) 496check_parse_path("eu/tu", { "eu", "tu" })
497 497
498print("testing path protection") 498print("testing path protection")
diff --git a/test/utestclnt.lua b/test/utestclnt.lua
index f002c6e..eec6adc 100644
--- a/test/utestclnt.lua
+++ b/test/utestclnt.lua
@@ -298,7 +298,7 @@ function empty_connect()
298 pass("ok") 298 pass("ok")
299 data = socket.connect(host, port) 299 data = socket.connect(host, port)
300 else 300 else
301 pass("gethostbyname returns localhost on empty string...") 301 pass("gethostbyname returns localhost on empty string...")
302 end 302 end
303end 303end
304 304