aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2003-03-20 00:24:44 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2003-03-20 00:24:44 +0000
commit53857360bb1ca9cd2080b69d930763ae59db9b06 (patch)
tree6c1bc6d6462695cf9048801b2244f7fd0cd21ad5
parent7da19138e37c4e0123860f1fecbceb80c3d2627d (diff)
downloadluasocket-53857360bb1ca9cd2080b69d930763ae59db9b06.tar.gz
luasocket-53857360bb1ca9cd2080b69d930763ae59db9b06.tar.bz2
luasocket-53857360bb1ca9cd2080b69d930763ae59db9b06.zip
Finish port to Lua 5. Everything is working fine.
Still doesn't work in Windows.
-rw-r--r--etc/check-links.lua58
-rw-r--r--etc/get.lua46
-rw-r--r--src/ftp.lua51
-rw-r--r--src/http.lua10
-rw-r--r--src/mbox.lua42
-rw-r--r--src/smtp.lua21
-rw-r--r--src/url.lua18
-rw-r--r--test/ftptest.lua118
-rw-r--r--test/httptest.lua18
-rw-r--r--test/smtptest.lua161
-rw-r--r--test/urltest.lua21
11 files changed, 288 insertions, 276 deletions
diff --git a/etc/check-links.lua b/etc/check-links.lua
index 24747a9..0dca27c 100644
--- a/etc/check-links.lua
+++ b/etc/check-links.lua
@@ -1,13 +1,9 @@
1dofile("../lua/http.lua") 1socket.http.TIMEOUT = 10
2HTTP.TIMEOUT = 10
3dofile("../lua/code.lua")
4dofile("../lua/url.lua")
5dofile("../lua/concat.lua")
6 2
7cache = {} 3cache = {}
8 4
9function readfile(path) 5function readfile(path)
10 path = Code.unescape(path) 6 path = socket.code.unescape(path)
11 local file, error = openfile(path, "r") 7 local file, error = openfile(path, "r")
12 if file then 8 if file then
13 local body = read(file, "*a") 9 local body = read(file, "*a")
@@ -17,7 +13,7 @@ function readfile(path)
17end 13end
18 14
19function getstatus(url) 15function getstatus(url)
20 local parsed = URL.parse_url(url, { scheme = "file" }) 16 local parsed = socket.url.parse(url, { scheme = "file" })
21 if cache[url] then return cache[url].res end 17 if cache[url] then return cache[url].res end
22 local res 18 local res
23 if parsed.scheme == "http" then 19 if parsed.scheme == "http" then
@@ -25,10 +21,10 @@ function getstatus(url)
25 local response = { body_cb = function(chunk, err) 21 local response = { body_cb = function(chunk, err)
26 return nil 22 return nil
27 end } 23 end }
28 local blocksize = HTTP.BLOCKSIZE 24 local blocksize = socket.http.BLOCKSIZE
29 HTTP.BLOCKSIZE = 1 25 socket.http.BLOCKSIZE = 1
30 response = HTTP.request_cb(request, response) 26 response = socket.http.request_cb(request, response)
31 HTTP.BLOCKSIZE = blocksize 27 socket.http.BLOCKSIZE = blocksize
32 if response.code == 200 then res = nil 28 if response.code == 200 then res = nil
33 else res = response.status or response.error end 29 else res = response.status or response.error end
34 elseif parsed.scheme == "file" then 30 elseif parsed.scheme == "file" then
@@ -37,17 +33,17 @@ function getstatus(url)
37 closefile(file) 33 closefile(file)
38 res = nil 34 res = nil
39 else res = error end 35 else res = error end
40 else res = format("unhandled scheme '%s'", parsed.scheme) end 36 else res = string.format("unhandled scheme '%s'", parsed.scheme) end
41 cache[url] = { res = res } 37 cache[url] = { res = res }
42 return res 38 return res
43end 39end
44 40
45function retrieve(url) 41function retrieve(url)
46 local parsed = URL.parse_url(url, { scheme = "file" }) 42 local parsed = socket.url.parse(url, { scheme = "file" })
47 local base, body, error 43 local base, body, error
48 base = url 44 base = url
49 if parsed.scheme == "http" then 45 if parsed.scheme == "http" then
50 local response = HTTP.request{url = url} 46 local response = socket.http.request{url = url}
51 if response.code ~= 200 then 47 if response.code ~= 200 then
52 error = response.status or response.error 48 error = response.status or response.error
53 else 49 else
@@ -56,23 +52,23 @@ function retrieve(url)
56 end 52 end
57 elseif parsed.scheme == "file" then 53 elseif parsed.scheme == "file" then
58 body, error = readfile(parsed.path) 54 body, error = readfile(parsed.path)
59 else error = format("unhandled scheme '%s'", parsed.scheme) end 55 else error = string.format("unhandled scheme '%s'", parsed.scheme) end
60 return base, body, error 56 return base, body, error
61end 57end
62 58
63function getlinks(body, base) 59function getlinks(body, base)
64 -- get rid of comments 60 -- get rid of comments
65 body = gsub(body, "%<%!%-%-.-%-%-%>", "") 61 body = string.gsub(body, "%<%!%-%-.-%-%-%>", "")
66 local links = {} 62 local links = {}
67 -- extract links 63 -- extract links
68 gsub(body, '[Hh][Rr][Ee][Ff]%s*=%s*"([^"]*)"', function(href) 64 string.gsub(body, '[Hh][Rr][Ee][Ff]%s*=%s*"([^"]*)"', function(href)
69 tinsert(%links, URL.absolute_url(%base, href)) 65 table.insert(links, socket.url.absolute(base, href))
70 end) 66 end)
71 gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*'([^']*)'", function(href) 67 string.gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*'([^']*)'", function(href)
72 tinsert(%links, URL.absolute_url(%base, href)) 68 table.insert(links, socket.url.absolute(base, href))
73 end) 69 end)
74 gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*(%a+)", function(href) 70 string.gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*(%a+)", function(href)
75 tinsert(%links, URL.absolute_url(%base, href)) 71 table.insert(links, socket.url.absolute(base, href))
76 end) 72 end)
77 return links 73 return links
78end 74end
@@ -81,19 +77,19 @@ function checklinks(url)
81 local base, body, error = retrieve(url) 77 local base, body, error = retrieve(url)
82 if not body then print(error) return end 78 if not body then print(error) return end
83 local links = getlinks(body, base) 79 local links = getlinks(body, base)
84 for i = 1, getn(links) do 80 for _, l in ipairs(links) do
85 write(_STDERR, "\t", links[i], "\n") 81 io.stderr:write("\t", l, "\n")
86 local err = getstatus(links[i]) 82 local err = getstatus(l)
87 if err then write('\t', links[i], ": ", err, "\n") end 83 if err then io.stderr:write('\t', l, ": ", err, "\n") end
88 end 84 end
89end 85end
90 86
91arg = arg or {} 87arg = arg or {}
92if getn(arg) < 1 then 88if table.getn(arg) < 1 then
93 write("Usage:\n luasocket -f check-links.lua {<url>}\n") 89 print("Usage:\n luasocket check-links.lua {<url>}")
94 exit() 90 exit()
95end 91end
96for i = 1, getn(arg) do 92for _, a in ipairs(arg) do
97 write("Checking ", arg[i], "\n") 93 print("Checking ", a)
98 checklinks(URL.absolute_url("file:", arg[i])) 94 checklinks(socket.url.absolute("file:", a))
99end 95end
diff --git a/etc/get.lua b/etc/get.lua
index ecfecd1..33da653 100644
--- a/etc/get.lua
+++ b/etc/get.lua
@@ -13,8 +13,8 @@ function nicetime(s)
13 end 13 end
14 end 14 end
15 end 15 end
16 if l == "s" then return format("%2.0f%s", s, l) 16 if l == "s" then return string.format("%2.0f%s", s, l)
17 else return format("%5.2f%s", s, l) end 17 else return string.format("%5.2f%s", s, l) end
18end 18end
19 19
20-- formats a number of bytes into human readable form 20-- formats a number of bytes into human readable form
@@ -32,21 +32,21 @@ function nicesize(b)
32 end 32 end
33 end 33 end
34 end 34 end
35 return format("%7.2f%2s", b, l) 35 return string.format("%7.2f%2s", b, l)
36end 36end
37 37
38-- returns a string with the current state of the download 38-- returns a string with the current state of the download
39function gauge(got, dt, size) 39function gauge(got, dt, size)
40 local rate = got / dt 40 local rate = got / dt
41 if size and size >= 1 then 41 if size and size >= 1 then
42 return format("%s received, %s/s throughput, " .. 42 return string.format("%s received, %s/s throughput, " ..
43 "%.0f%% done, %s remaining", 43 "%.0f%% done, %s remaining",
44 nicesize(got), 44 nicesize(got),
45 nicesize(rate), 45 nicesize(rate),
46 100*got/size, 46 100*got/size,
47 nicetime((size-got)/rate)) 47 nicetime((size-got)/rate))
48 else 48 else
49 return format("%s received, %s/s throughput, %s elapsed", 49 return string.format("%s received, %s/s throughput, %s elapsed",
50 nicesize(got), 50 nicesize(got),
51 nicesize(rate), 51 nicesize(rate),
52 nicetime(dt)) 52 nicetime(dt))
@@ -57,22 +57,22 @@ end
57-- kind of copied from luasocket's manual callback examples 57-- kind of copied from luasocket's manual callback examples
58function receive2disk(file, size) 58function receive2disk(file, size)
59 local aux = { 59 local aux = {
60 start = _time(), 60 start = socket._time(),
61 got = 0, 61 got = 0,
62 file = openfile(file, "wb"), 62 file = io.open(file, "wb"),
63 size = size 63 size = size
64 } 64 }
65 local receive_cb = function(chunk, err) 65 local receive_cb = function(chunk, err)
66 local dt = _time() - %aux.start -- elapsed time since start 66 local dt = socket._time() - %aux.start -- elapsed time since start
67 if not chunk or chunk == "" then 67 if not chunk or chunk == "" then
68 write("\n") 68 io.write("\n")
69 closefile(%aux.file) 69 aux.file:close()
70 return 70 return
71 end 71 end
72 write(%aux.file, chunk) 72 aux.file:write(chunk)
73 %aux.got = %aux.got + strlen(chunk) -- total bytes received 73 aux.got = aux.got + string.len(chunk) -- total bytes received
74 if dt < 0.1 then return 1 end -- not enough time for estimate 74 if dt < 0.1 then return 1 end -- not enough time for estimate
75 write("\r", gauge(%aux.got, dt, %aux.size)) 75 io.write("\r", gauge(aux.got, dt, aux.size))
76 return 1 76 return 1
77 end 77 end
78 return receive_cb 78 return receive_cb
@@ -80,7 +80,7 @@ end
80 80
81-- downloads a file using the ftp protocol 81-- downloads a file using the ftp protocol
82function getbyftp(url, file) 82function getbyftp(url, file)
83 local err = FTP.get_cb { 83 local err = socket.ftp.get_cb {
84 url = url, 84 url = url,
85 content_cb = receive2disk(file), 85 content_cb = receive2disk(file),
86 type = "i" 86 type = "i"
@@ -91,7 +91,7 @@ end
91 91
92-- downloads a file using the http protocol 92-- downloads a file using the http protocol
93function getbyhttp(url, file, size) 93function getbyhttp(url, file, size)
94 local response = HTTP.request_cb( 94 local response = socket.http.request_cb(
95 {url = url}, 95 {url = url},
96 {body_cb = receive2disk(file, size)} 96 {body_cb = receive2disk(file, size)}
97 ) 97 )
@@ -101,7 +101,7 @@ end
101 101
102-- determines the size of a http file 102-- determines the size of a http file
103function gethttpsize(url) 103function gethttpsize(url)
104 local response = HTTP.request { 104 local response = socket.http.request {
105 method = "HEAD", 105 method = "HEAD",
106 url = url 106 url = url
107 } 107 }
@@ -113,11 +113,11 @@ end
113-- determines the scheme and the file name of a given url 113-- determines the scheme and the file name of a given url
114function getschemeandname(url, name) 114function getschemeandname(url, name)
115 -- this is an heuristic to solve a common invalid url poblem 115 -- this is an heuristic to solve a common invalid url poblem
116 if not strfind(url, "//") then url = "//" .. url end 116 if not string.find(url, "//") then url = "//" .. url end
117 local parsed = URL.parse_url(url, {scheme = "http"}) 117 local parsed = socket.url.parse(url, {scheme = "http"})
118 if name then return parsed.scheme, name end 118 if name then return parsed.scheme, name end
119 local segment = URL.parse_path(parsed.path) 119 local segment = socket.url.parse_path(parsed.path)
120 name = segment[getn(segment)] 120 name = segment[table.getn(segment)]
121 if segment.is_directory then name = nil end 121 if segment.is_directory then name = nil end
122 return parsed.scheme, name 122 return parsed.scheme, name
123end 123end
@@ -134,7 +134,7 @@ end
134 134
135-- main program 135-- main program
136arg = arg or {} 136arg = arg or {}
137if getn(arg) < 1 then 137if table.getn(arg) < 1 then
138 write("Usage:\n luasocket -f get.lua <remote-url> [<local-file>]\n") 138 io.write("Usage:\n luasocket get.lua <remote-url> [<local-file>]\n")
139 exit(1) 139 os.exit(1)
140else get(arg[1], arg[2]) end 140else get(arg[1], arg[2]) end
diff --git a/src/ftp.lua b/src/ftp.lua
index 1fa48f7..f6fffbb 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -8,7 +8,7 @@
8----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
9 9
10local Public, Private = {}, {} 10local Public, Private = {}, {}
11FTP = Public 11socket.ftp = Public
12 12
13----------------------------------------------------------------------------- 13-----------------------------------------------------------------------------
14-- Program constants 14-- Program constants
@@ -47,7 +47,7 @@ end
47----------------------------------------------------------------------------- 47-----------------------------------------------------------------------------
48function Private.try_receive(...) 48function Private.try_receive(...)
49 local sock = arg[1] 49 local sock = arg[1]
50 local data, err = call(sock.receive, arg) 50 local data, err = sock.receive(unpack(arg))
51 if err then sock:close() end 51 if err then sock:close() end
52 return data, err 52 return data, err
53end 53end
@@ -64,9 +64,9 @@ function Private.get_pasv(pasv)
64 local a, b, c, d, p1, p2, _ 64 local a, b, c, d, p1, p2, _
65 local ip, port 65 local ip, port
66 _,_, a, b, c, d, p1, p2 = 66 _,_, a, b, c, d, p1, p2 =
67 strfind(pasv, "(%d*),(%d*),(%d*),(%d*),(%d*),(%d*)") 67 string.find(pasv, "(%d*),(%d*),(%d*),(%d*),(%d*),(%d*)")
68 if not (a and b and c and d and p1 and p2) then return nil, nil end 68 if not (a and b and c and d and p1 and p2) then return nil, nil end
69 ip = format("%d.%d.%d.%d", a, b, c, d) 69 ip = string.format("%d.%d.%d.%d", a, b, c, d)
70 port = tonumber(p1)*256 + tonumber(p2) 70 port = tonumber(p1)*256 + tonumber(p2)
71 return ip, port 71 return ip, port
72end 72end
@@ -100,13 +100,13 @@ function Private.get_answer(control)
100 local line, err = Private.try_receive(control) 100 local line, err = Private.try_receive(control)
101 local answer = line 101 local answer = line
102 if err then return nil, err end 102 if err then return nil, err end
103 _,_, code, sep = strfind(line, "^(%d%d%d)(.)") 103 _,_, code, sep = string.find(line, "^(%d%d%d)(.)")
104 if not code or not sep then return nil, answer end 104 if not code or not sep then return nil, answer end
105 if sep == "-" then -- answer is multiline 105 if sep == "-" then -- answer is multiline
106 repeat 106 repeat
107 line, err = Private.try_receive(control) 107 line, err = Private.try_receive(control)
108 if err then return nil, err end 108 if err then return nil, err end
109 _,_, lastcode, sep = strfind(line, "^(%d%d%d)(.)") 109 _,_, lastcode, sep = string.find(line, "^(%d%d%d)(.)")
110 answer = answer .. "\n" .. line 110 answer = answer .. "\n" .. line
111 until code == lastcode and sep == " " -- answer ends with same code 111 until code == lastcode and sep == " " -- answer ends with same code
112 end 112 end
@@ -126,8 +126,8 @@ function Private.check_answer(control, success)
126 local answer, code = Private.get_answer(control) 126 local answer, code = Private.get_answer(control)
127 if not answer then return nil, code end 127 if not answer then return nil, code end
128 if type(success) ~= "table" then success = {success} end 128 if type(success) ~= "table" then success = {success} end
129 for i = 1, getn(success) do 129 for _, s in ipairs(success) do
130 if code == success[i] then 130 if code == s then
131 return code, answer 131 return code, answer
132 end 132 end
133 end 133 end
@@ -213,13 +213,13 @@ function Private.port(control)
213 local code, answer 213 local code, answer
214 local server, ctl_ip 214 local server, ctl_ip
215 ctl_ip, answer = control:getsockname() 215 ctl_ip, answer = control:getsockname()
216 server, answer = bind(ctl_ip, 0) 216 server, answer = socket.bind(ctl_ip, 0)
217 server:timeout(Public.TIMEOUT) 217 server:timeout(Public.TIMEOUT)
218 local ip, p, ph, pl 218 local ip, p, ph, pl
219 ip, p = server:getsockname() 219 ip, p = server:getsockname()
220 pl = mod(p, 256) 220 pl = math.mod(p, 256)
221 ph = (p - pl)/256 221 ph = (p - pl)/256
222 local arg = gsub(format("%s,%d,%d", ip, ph, pl), "%.", ",") 222 local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
223 code, answer = Private.command(control, "port", arg, {200}) 223 code, answer = Private.command(control, "port", arg, {200})
224 if not code then 224 if not code then
225 server:close() 225 server:close()
@@ -321,7 +321,7 @@ function Private.send_indirect(data, send_cb, chunk, size)
321 data:close() 321 data:close()
322 return err 322 return err
323 end 323 end
324 sent = sent + strlen(chunk) 324 sent = sent + string.len(chunk)
325 if sent >= size then break end 325 if sent >= size then break end
326 chunk, size = send_cb() 326 chunk, size = send_cb()
327 end 327 end
@@ -374,7 +374,7 @@ end
374----------------------------------------------------------------------------- 374-----------------------------------------------------------------------------
375function Private.change_type(control, params) 375function Private.change_type(control, params)
376 local type, _ 376 local type, _
377 _, _, type = strfind(params or "", "type=(.)") 377 _, _, type = string.find(params or "", "type=(.)")
378 if type == "a" or type == "i" then 378 if type == "a" or type == "i" then
379 local code, err = Private.command(control, "type", type, {200}) 379 local code, err = Private.command(control, "type", type, {200})
380 if not code then return err end 380 if not code then return err end
@@ -391,7 +391,7 @@ end
391----------------------------------------------------------------------------- 391-----------------------------------------------------------------------------
392function Private.open(parsed) 392function Private.open(parsed)
393 -- start control connection 393 -- start control connection
394 local control, err = connect(parsed.host, parsed.port) 394 local control, err = socket.connect(parsed.host, parsed.port)
395 if not control then return nil, err end 395 if not control then return nil, err end
396 -- make sure we don't block forever 396 -- make sure we don't block forever
397 control:timeout(Public.TIMEOUT) 397 control:timeout(Public.TIMEOUT)
@@ -423,7 +423,7 @@ end
423-- err: error message if any 423-- err: error message if any
424----------------------------------------------------------------------------- 424-----------------------------------------------------------------------------
425function Private.change_dir(control, segment) 425function Private.change_dir(control, segment)
426 local n = getn(segment) 426 local n = table.getn(segment)
427 for i = 1, n-1 do 427 for i = 1, n-1 do
428 local code, answer = Private.cwd(control, segment[i]) 428 local code, answer = Private.cwd(control, segment[i])
429 if not code then return answer end 429 if not code then return answer end
@@ -443,7 +443,7 @@ end
443function Private.upload(control, request, segment) 443function Private.upload(control, request, segment)
444 local code, name, content_cb 444 local code, name, content_cb
445 -- get remote file name 445 -- get remote file name
446 name = segment[getn(segment)] 446 name = segment[table.getn(segment)]
447 if not name then 447 if not name then
448 control:close() 448 control:close()
449 return "Invalid file path" 449 return "Invalid file path"
@@ -472,7 +472,7 @@ function Private.download(control, request, segment)
472 is_directory = segment.is_directory 472 is_directory = segment.is_directory
473 content_cb = request.content_cb 473 content_cb = request.content_cb
474 -- get remote file name 474 -- get remote file name
475 name = segment[getn(segment)] 475 name = segment[table.getn(segment)]
476 if not name and not is_directory then 476 if not name and not is_directory then
477 control:close() 477 control:close()
478 return "Invalid file path" 478 return "Invalid file path"
@@ -498,7 +498,7 @@ end
498-- parsed: a table with parsed components 498-- parsed: a table with parsed components
499----------------------------------------------------------------------------- 499-----------------------------------------------------------------------------
500function Private.parse_url(request) 500function Private.parse_url(request)
501 local parsed = URL.parse_url(request.url, { 501 local parsed = socket.url.parse(request.url, {
502 host = "", 502 host = "",
503 user = "anonymous", 503 user = "anonymous",
504 port = 21, 504 port = 21,
@@ -521,9 +521,10 @@ end
521-- Returns 521-- Returns
522-- dirs: a table with parsed directory components 522-- dirs: a table with parsed directory components
523----------------------------------------------------------------------------- 523-----------------------------------------------------------------------------
524function Private.parse_path(parsed) 524function Private.parse_path(parsed_url)
525 local segment = URL.parse_path(parsed.path) 525 local segment = socket.url.parse_path(parsed_url.path)
526 segment.is_directory = segment.is_directory or (parsed.params == "type=d") 526 segment.is_directory = segment.is_directory or
527 (parsed_url.params == "type=d")
527 return segment 528 return segment
528end 529end
529 530
@@ -560,7 +561,7 @@ end
560function Public.get_cb(request) 561function Public.get_cb(request)
561 local parsed = Private.parse_url(request) 562 local parsed = Private.parse_url(request)
562 if parsed.scheme ~= "ftp" then 563 if parsed.scheme ~= "ftp" then
563 return format("unknown scheme '%s'", parsed.scheme) 564 return string.format("unknown scheme '%s'", parsed.scheme)
564 end 565 end
565 local control, err = Private.open(parsed) 566 local control, err = Private.open(parsed)
566 if not control then return err end 567 if not control then return err end
@@ -586,7 +587,7 @@ end
586function Public.put_cb(request) 587function Public.put_cb(request)
587 local parsed = Private.parse_url(request) 588 local parsed = Private.parse_url(request)
588 if parsed.scheme ~= "ftp" then 589 if parsed.scheme ~= "ftp" then
589 return format("unknown scheme '%s'", parsed.scheme) 590 return string.format("unknown scheme '%s'", parsed.scheme)
590 end 591 end
591 local control, err = Private.open(parsed) 592 local control, err = Private.open(parsed)
592 if not control then return err end 593 if not control then return err end
@@ -612,7 +613,7 @@ end
612function Public.put(url_or_request, content) 613function Public.put(url_or_request, content)
613 local request = Private.build_request(url_or_request) 614 local request = Private.build_request(url_or_request)
614 request.content_cb = function() 615 request.content_cb = function()
615 return content, strlen(content) 616 return content, string.len(content)
616 end 617 end
617 return Public.put_cb(request) 618 return Public.put_cb(request)
618end 619end
@@ -630,7 +631,7 @@ end
630-- err: error message in case of error, nil otherwise 631-- err: error message in case of error, nil otherwise
631----------------------------------------------------------------------------- 632-----------------------------------------------------------------------------
632function Public.get(url_or_request) 633function Public.get(url_or_request)
633 local cat = Concat.create() 634 local cat = socket.concat.create()
634 local request = Private.build_request(url_or_request) 635 local request = Private.build_request(url_or_request)
635 request.content_cb = function(chunk, err) 636 request.content_cb = function(chunk, err)
636 if chunk then cat:addstring(chunk) end 637 if chunk then cat:addstring(chunk) end
diff --git a/src/http.lua b/src/http.lua
index 9543d59..3275e3b 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -8,7 +8,7 @@
8----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
9 9
10local Public, Private = {}, {} 10local Public, Private = {}, {}
11http = Public 11socket.http = Public
12 12
13----------------------------------------------------------------------------- 13-----------------------------------------------------------------------------
14-- Program constants 14-- Program constants
@@ -427,7 +427,7 @@ end
427----------------------------------------------------------------------------- 427-----------------------------------------------------------------------------
428function Private.authorize(request, parsed, response) 428function Private.authorize(request, parsed, response)
429 request.headers["authorization"] = "Basic " .. 429 request.headers["authorization"] = "Basic " ..
430 Code.base64(parsed.user .. ":" .. parsed.password) 430 socket.code.base64(parsed.user .. ":" .. parsed.password)
431 local authorize = { 431 local authorize = {
432 redirects = request.redirects, 432 redirects = request.redirects,
433 method = request.method, 433 method = request.method,
@@ -471,7 +471,7 @@ function Private.redirect(request, response)
471 method = request.method, 471 method = request.method,
472 -- the RFC says the redirect URL has to be absolute, but some 472 -- the RFC says the redirect URL has to be absolute, but some
473 -- servers do not respect that 473 -- servers do not respect that
474 url = URL.absolute_url(request.url, response.headers["location"]), 474 url = socket.url.absolute(request.url, response.headers["location"]),
475 body_cb = request.body_cb, 475 body_cb = request.body_cb,
476 headers = request.headers 476 headers = request.headers
477 } 477 }
@@ -535,7 +535,7 @@ end
535-- error: error message, or nil if successfull 535-- error: error message, or nil if successfull
536----------------------------------------------------------------------------- 536-----------------------------------------------------------------------------
537function Public.request_cb(request, response) 537function Public.request_cb(request, response)
538 local parsed = URL.parse_url(request.url, { 538 local parsed = socket.url.parse(request.url, {
539 host = "", 539 host = "",
540 port = Public.PORT, 540 port = Public.PORT,
541 path ="/", 541 path ="/",
@@ -622,7 +622,7 @@ function Public.request(request)
622 return request.body, string.len(request.body) 622 return request.body, string.len(request.body)
623 end 623 end
624 end 624 end
625 local cat = Concat.create() 625 local cat = socket.concat.create()
626 response.body_cb = function(chunk, err) 626 response.body_cb = function(chunk, err)
627 if chunk then cat:addstring(chunk) end 627 if chunk then cat:addstring(chunk) end
628 return 1 628 return 1
diff --git a/src/mbox.lua b/src/mbox.lua
index 2969111..4a72331 100644
--- a/src/mbox.lua
+++ b/src/mbox.lua
@@ -4,11 +4,11 @@ mbox = Public
4 4
5function Public.split_message(message_s) 5function Public.split_message(message_s)
6 local message = {} 6 local message = {}
7 message_s = gsub(message_s, "\r\n", "\n") 7 message_s = string.gsub(message_s, "\r\n", "\n")
8 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 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 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
@@ -18,26 +18,26 @@ end
18 18
19function Public.split_headers(headers_s) 19function Public.split_headers(headers_s)
20 local headers = {} 20 local headers = {}
21 headers_s = gsub(headers_s, "\r\n", "\n") 21 headers_s = string.gsub(headers_s, "\r\n", "\n")
22 headers_s = gsub(headers_s, "\n[ ]+", " ") 22 headers_s = string.gsub(headers_s, "\n[ ]+", " ")
23 gsub("\n" .. headers_s, "\n([^\n]+)", function (h) tinsert(%headers, h) end) 23 string.gsub("\n" .. headers_s, "\n([^\n]+)", function (h) table.insert(%headers, h) end)
24 return headers 24 return headers
25end 25end
26 26
27function Public.parse_header(header_s) 27function Public.parse_header(header_s)
28 header_s = gsub(header_s, "\n[ ]+", " ") 28 header_s = string.gsub(header_s, "\n[ ]+", " ")
29 header_s = gsub(header_s, "\n+", "") 29 header_s = string.gsub(header_s, "\n+", "")
30 local _, __, name, value = strfind(header_s, "([^%s:]-):%s*(.*)") 30 local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)")
31 return name, value 31 return name, value
32end 32end
33 33
34function Public.parse_headers(headers_s) 34function Public.parse_headers(headers_s)
35 local headers_t = %Public.split_headers(headers_s) 35 local headers_t = %Public.split_headers(headers_s)
36 local headers = {} 36 local headers = {}
37 for i = 1, getn(headers_t) do 37 for i = 1, table.getn(headers_t) do
38 local name, value = %Public.parse_header(headers_t[i]) 38 local name, value = %Public.parse_header(headers_t[i])
39 if name then 39 if name then
40 name = strlower(name) 40 name = string.lower(name)
41 if headers[name] then 41 if headers[name] then
42 headers[name] = headers[name] .. ", " .. value 42 headers[name] = headers[name] .. ", " .. value
43 else headers[name] = value end 43 else headers[name] = value end
@@ -47,34 +47,34 @@ function Public.parse_headers(headers_s)
47end 47end
48 48
49function Public.parse_from(from) 49function Public.parse_from(from)
50 local _, __, name, address = strfind(from, "^%s*(.-)%s*%<(.-)%>") 50 local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>")
51 if not address then 51 if not address then
52 _, __, address = strfind(from, "%s*(.+)%s*") 52 _, __, address = string.find(from, "%s*(.+)%s*")
53 end 53 end
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 = 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 = 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 = strfind(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 = strsub(mbox_s, j, i-1) 68 local message = string.sub(mbox_s, j, i-1)
69 tinsert(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(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, 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
diff --git a/src/smtp.lua b/src/smtp.lua
index 774dddb..5da9a6f 100644
--- a/src/smtp.lua
+++ b/src/smtp.lua
@@ -8,7 +8,7 @@
8----------------------------------------------------------------------------- 8-----------------------------------------------------------------------------
9 9
10local Public, Private = {}, {} 10local Public, Private = {}, {}
11SMTP = Public 11socket.smtp = Public
12 12
13----------------------------------------------------------------------------- 13-----------------------------------------------------------------------------
14-- Program constants 14-- Program constants
@@ -47,7 +47,7 @@ end
47----------------------------------------------------------------------------- 47-----------------------------------------------------------------------------
48function Private.try_receive(...) 48function Private.try_receive(...)
49 local sock = arg[1] 49 local sock = arg[1]
50 local data, err = call(sock.receive, arg) 50 local data, err = sock.receive(unpack(arg))
51 if err then sock:close() end 51 if err then sock:close() end
52 return data, err 52 return data, err
53end 53end
@@ -81,13 +81,13 @@ function Private.get_answer(control)
81 local line, err = Private.try_receive(control) 81 local line, err = Private.try_receive(control)
82 local answer = line 82 local answer = line
83 if err then return nil, err end 83 if err then return nil, err end
84 _,_, code, sep = strfind(line, "^(%d%d%d)(.)") 84 _,_, code, sep = string.find(line, "^(%d%d%d)(.)")
85 if not code or not sep then return nil, answer end 85 if not code or not sep then return nil, answer end
86 if sep == "-" then -- answer is multiline 86 if sep == "-" then -- answer is multiline
87 repeat 87 repeat
88 line, err = Private.try_receive(control) 88 line, err = Private.try_receive(control)
89 if err then return nil, err end 89 if err then return nil, err end
90 _,_, lastcode, sep = strfind(line, "^(%d%d%d)(.)") 90 _,_, lastcode, sep = string.find(line, "^(%d%d%d)(.)")
91 answer = answer .. "\n" .. line 91 answer = answer .. "\n" .. line
92 until code == lastcode and sep == " " -- answer ends with same code 92 until code == lastcode and sep == " " -- answer ends with same code
93 end 93 end
@@ -108,7 +108,7 @@ function Private.check_answer(control, success)
108 local answer, code = Private.get_answer(control) 108 local answer, code = Private.get_answer(control)
109 if not answer then return nil, code end 109 if not answer then return nil, code end
110 if type(success) ~= "table" then success = {success} end 110 if type(success) ~= "table" then success = {success} end
111 for i = 1, getn(success) do 111 for i = 1, table.getn(success) do
112 if code == success[i] then 112 if code == success[i] then
113 return code, answer 113 return code, answer
114 end 114 end
@@ -157,7 +157,7 @@ end
157-- answer: complete server reply or error message 157-- answer: complete server reply or error message
158----------------------------------------------------------------------------- 158-----------------------------------------------------------------------------
159function Private.send_mail(sock, sender) 159function Private.send_mail(sock, sender)
160 local param = format("FROM:<%s>", sender or "") 160 local param = string.format("FROM:<%s>", sender or "")
161 local err = Private.send_command(sock, "MAIL", param) 161 local err = Private.send_command(sock, "MAIL", param)
162 if err then return nil, err end 162 if err then return nil, err end
163 return Private.check_answer(sock, 250) 163 return Private.check_answer(sock, 250)
@@ -198,7 +198,7 @@ function Private.send_data(sock, headers, body)
198 local code, answer = Private.check_answer(sock, 354) 198 local code, answer = Private.check_answer(sock, 354)
199 if not code then return nil, answer end 199 if not code then return nil, answer end
200 -- avoid premature end in message body 200 -- avoid premature end in message body
201 body = gsub(body or "", "\n%.", "\n%.%.") 201 body = string.gsub(body or "", "\n%.", "\n%.%.")
202 -- mark end of message body 202 -- mark end of message body
203 body = body .. "\r\n.\r\n" 203 body = body .. "\r\n.\r\n"
204 err = Private.send_headers(sock, headers) 204 err = Private.send_headers(sock, headers)
@@ -220,8 +220,9 @@ function Private.send_rcpt(sock, rcpt)
220 local err 220 local err
221 local code, answer = nil, "No recipient specified" 221 local code, answer = nil, "No recipient specified"
222 if type(rcpt) ~= "table" then rcpt = {rcpt} end 222 if type(rcpt) ~= "table" then rcpt = {rcpt} end
223 for i = 1, getn(rcpt) do 223 for i = 1, table.getn(rcpt) do
224 err = Private.send_command(sock, "RCPT", format("TO:<%s>", rcpt[i])) 224 err = Private.send_command(sock, "RCPT",
225 string.format("TO:<%s>", rcpt[i]))
225 if err then return nil, err end 226 if err then return nil, err end
226 code, answer = Private.check_answer(sock, {250, 251}) 227 code, answer = Private.check_answer(sock, {250, 251})
227 if not code then return code, answer end 228 if not code then return code, answer end
@@ -242,7 +243,7 @@ function Private.open(server)
242 -- default server 243 -- default server
243 server = server or Public.SERVER 244 server = server or Public.SERVER
244 -- connect to server and make sure we won't hang 245 -- connect to server and make sure we won't hang
245 local sock, err = connect(server, Public.PORT) 246 local sock, err = socket.connect(server, Public.PORT)
246 if not sock then return nil, err end 247 if not sock then return nil, err end
247 sock:timeout(Public.TIMEOUT) 248 sock:timeout(Public.TIMEOUT)
248 -- initial server greeting 249 -- initial server greeting
diff --git a/src/url.lua b/src/url.lua
index 4d2bfa7..2cf9669 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -8,7 +8,7 @@
8---------------------------------------------------------------------------- 8----------------------------------------------------------------------------
9 9
10local Public, Private = {}, {} 10local Public, Private = {}, {}
11URL = Public 11socket.url = Public
12 12
13----------------------------------------------------------------------------- 13-----------------------------------------------------------------------------
14-- Parses a url and returns a table with all its parts according to RFC 2396 14-- Parses a url and returns a table with all its parts according to RFC 2396
@@ -28,7 +28,7 @@ URL = Public
28-- Obs: 28-- Obs:
29-- the leading '/' in {/<path>} is considered part of <path> 29-- the leading '/' in {/<path>} is considered part of <path>
30----------------------------------------------------------------------------- 30-----------------------------------------------------------------------------
31function Public.parse_url(url, default) 31function Public.parse(url, default)
32 -- initialize default parameters 32 -- initialize default parameters
33 local parsed = default or {} 33 local parsed = default or {}
34 -- empty url is parsed to nil 34 -- empty url is parsed to nil
@@ -70,7 +70,7 @@ end
70-- Returns 70-- Returns
71-- a stringing with the corresponding URL 71-- a stringing with the corresponding URL
72----------------------------------------------------------------------------- 72-----------------------------------------------------------------------------
73function Public.build_url(parsed) 73function Public.build(parsed)
74 local url = parsed.path or "" 74 local url = parsed.path or ""
75 if parsed.params then url = url .. ";" .. parsed.params end 75 if parsed.params then url = url .. ";" .. parsed.params end
76 if parsed.query then url = url .. "?" .. parsed.query end 76 if parsed.query then url = url .. "?" .. parsed.query end
@@ -102,9 +102,9 @@ end
102-- Returns 102-- Returns
103-- corresponding absolute url 103-- corresponding absolute url
104----------------------------------------------------------------------------- 104-----------------------------------------------------------------------------
105function Public.absolute_url(base_url, relative_url) 105function Public.absolute(base_url, relative_url)
106 local base = Public.parse_url(base_url) 106 local base = Public.parse(base_url)
107 local relative = Public.parse_url(relative_url) 107 local relative = Public.parse(relative_url)
108 if not base then return relative_url 108 if not base then return relative_url
109 elseif not relative then return base_url 109 elseif not relative then return base_url
110 elseif relative.scheme then return relative_url 110 elseif relative.scheme then return relative_url
@@ -124,7 +124,7 @@ function Public.absolute_url(base_url, relative_url)
124 relative.path = Private.absolute_path(base.path,relative.path) 124 relative.path = Private.absolute_path(base.path,relative.path)
125 end 125 end
126 end 126 end
127 return Public.build_url(relative) 127 return Public.build(relative)
128 end 128 end
129end 129end
130 130
@@ -141,7 +141,7 @@ function Public.parse_path(path)
141 path = string.gsub(path, "%s", "") 141 path = string.gsub(path, "%s", "")
142 string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) 142 string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
143 for i = 1, table.getn(parsed) do 143 for i = 1, table.getn(parsed) do
144 parsed[i] = Code.unescape(parsed[i]) 144 parsed[i] = socket.code.unescape(parsed[i])
145 end 145 end
146 if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end 146 if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
147 if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end 147 if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
@@ -201,7 +201,7 @@ function Private.protect_segment(s)
201 local segment_set = Private.segment_set 201 local segment_set = Private.segment_set
202 return string.gsub(s, "(%W)", function (c) 202 return string.gsub(s, "(%W)", function (c)
203 if segment_set[c] then return c 203 if segment_set[c] then return c
204 else return Code.escape(c) end 204 else return socket.code.escape(c) end
205 end) 205 end)
206end 206end
207 207
diff --git a/test/ftptest.lua b/test/ftptest.lua
index 34cccf1..ee3af91 100644
--- a/test/ftptest.lua
+++ b/test/ftptest.lua
@@ -1,29 +1,32 @@
1dofile("noglobals.lua") 1dofile("noglobals.lua")
2 2
3local similar = function(s1, s2) 3local similar = function(s1, s2)
4 return strlower(gsub(s1, "%s", "")) == strlower(gsub(s2, "%s", "")) 4 return
5 string.lower(string.gsub(s1, "%s", "")) ==
6 string.lower(string.gsub(s2, "%s", ""))
5end 7end
6 8
7local capture = function(cmd) 9local readfile = function(name)
8 readfrom("| " .. cmd) 10 local f = io.open(name, "r")
9 local s = read("*a") 11 if not f then return nil end
10 readfrom() 12 local s = f:read("*a")
13 f:close()
11 return s 14 return s
12end 15end
13 16
14local readfile = function(name) 17local capture = function(cmd)
15 local f = readfrom(name) 18 local f = io.popen(cmd)
16 if not f then return nil end 19 if not f then return nil end
17 local s = read("*a") 20 local s = f:read("*a")
18 readfrom() 21 f:close()
19 return s 22 return s
20end 23end
21 24
22local check = function(v, e, o) 25local check = function(v, e, o)
23 e = e or "failed!" 26 e = e or "failed!"
24 o = o or "ok" 27 o = o or "ok"
25 if v then print(o) 28 if v then print(o)
26 else print(e) exit() end 29 else print(e) os.exit() end
27end 30end
28 31
29-- needs an account luasocket:password 32-- needs an account luasocket:password
@@ -31,81 +34,82 @@ end
31 34
32local index, err, saved, back, expected 35local index, err, saved, back, expected
33 36
34local t = _time() 37local t = socket._time()
35 38
36index = readfile("index.html") 39index = readfile("test/index.html")
40
41io.write("testing wrong scheme: ")
42back, err = socket.ftp.get("wrong://banana.com/lixo")
43check(not back and err == "unknown scheme 'wrong'", err)
44
45io.write("testing invalid url: ")
46back, err = socket.ftp.get("localhost/dir1/index.html;type=i")
47local c, e = socket.connect("", 21)
48check(not back and err == e, err)
37 49
38write("testing file upload: ") 50io.write("testing anonymous file upload: ")
39remove("/var/ftp/dir1/index.up.html") 51os.remove("/var/ftp/pub/index.up.html")
40err = FTP.put("ftp://localhost/dir1/index.up.html;type=i", index) 52err = socket.ftp.put("ftp://localhost/pub/index.up.html;type=i", index)
41saved = readfile("/var/ftp/dir1/index.up.html") 53saved = readfile("/var/ftp/pub/index.up.html")
42check(not err and saved == index, err) 54check(not err and saved == index, err)
43 55
44write("testing file download: ") 56io.write("testing anonymous file download: ")
45back, err = FTP.get("ftp://localhost/dir1/index.up.html;type=i") 57back, err = socket.ftp.get("ftp://localhost/pub/index.up.html;type=i")
46check(not err and back == index, err) 58check(not err and back == index, err)
47 59
48write("testing no directory changes: ") 60io.write("testing no directory changes: ")
49back, err = FTP.get("ftp://localhost/index.html;type=i") 61back, err = socket.ftp.get("ftp://localhost/index.html;type=i")
50check(not err and back == index, err) 62check(not err and back == index, err)
51 63
52write("testing multiple directory changes: ") 64io.write("testing multiple directory changes: ")
53back, err = FTP.get("ftp://localhost/dir1/dir2/dir3/dir4/dir5/dir6/index.html;type=i") 65back, err = socket.ftp.get("ftp://localhost/pub/dir1/dir2/dir3/dir4/dir5/index.html;type=i")
54check(not err and back == index, err) 66check(not err and back == index, err)
55 67
56write("testing authenticated upload: ") 68io.write("testing authenticated upload: ")
57remove("/home/luasocket/index.up.html") 69os.remove("/home/luasocket/index.up.html")
58err = FTP.put("ftp://luasocket:password@localhost/index.up.html;type=i", index) 70err = socket.ftp.put("ftp://luasocket:password@localhost/index.up.html;type=i", index)
59saved = readfile("/home/luasocket/index.up.html") 71saved = readfile("/home/luasocket/index.up.html")
60check(not err and saved == index, err) 72check(not err and saved == index, err)
61 73
62write("testing authenticated download: ") 74io.write("testing authenticated download: ")
63back, err = FTP.get("ftp://luasocket:password@localhost/index.up.html;type=i") 75back, err = socket.ftp.get("ftp://luasocket:password@localhost/index.up.html;type=i")
64check(not err and back == index, err) 76check(not err and back == index, err)
65 77
66write("testing weird-character translation: ") 78io.write("testing weird-character translation: ")
67back, err = FTP.get("ftp://luasocket:password@localhost/%2fvar/ftp/dir1/index.html;type=i") 79back, err = socket.ftp.get("ftp://luasocket:password@localhost/%2fvar/ftp/pub/index.html;type=i")
68check(not err and back == index, err) 80check(not err and back == index, err)
69 81
70write("testing parameter overriding: ") 82io.write("testing parameter overriding: ")
71back, err = FTP.get { 83back, err = socket.ftp.get {
72 url = "//stupid:mistake@localhost/dir1/index.html", 84 url = "//stupid:mistake@localhost/index.html",
73 user = "luasocket", 85 user = "luasocket",
74 password = "password", 86 password = "password",
75 type = "i" 87 type = "i"
76} 88}
77check(not err and back == index, err) 89check(not err and back == index, err)
78 90
79write("testing wrong scheme: ") 91io.write("testing home directory listing: ")
80back, err = FTP.get("wrong://banana.com/lixo")
81check(not back and err == "unknown scheme 'wrong'", err)
82
83write("testing invalid url: ")
84back, err = FTP.get("localhost/dir1/index.html;type=i")
85local c, e = connect("", 21)
86check(not back and err == e, err)
87
88write("testing directory listing: ")
89expected = capture("ls -F /var/ftp/dir1 | grep -v /")
90back, err = FTP.get("ftp://localhost/dir1;type=d")
91check(similar(back, expected))
92
93write("testing home directory listing: ")
94expected = capture("ls -F /var/ftp | grep -v /") 92expected = capture("ls -F /var/ftp | grep -v /")
95back, err = FTP.get("ftp://localhost/") 93back, err = socket.ftp.get("ftp://localhost/")
96check(back and similar(back, expected), nil, err) 94check(back and similar(back, expected), nil, err)
97 95
98write("testing upload denial: ") 96io.write("testing directory listing: ")
99err = FTP.put("ftp://localhost/index.up.html;type=a", index) 97expected = capture("ls -F /var/ftp/pub | grep -v /")
98back, err = socket.ftp.get("ftp://localhost/pub;type=d")
99check(similar(back, expected))
100
101io.write("testing upload denial: ")
102err = socket.ftp.put("ftp://localhost/index.up.html;type=a", index)
100check(err, err) 103check(err, err)
101 104
102write("testing authentication failure: ") 105io.write("testing authentication failure: ")
103err = FTP.put("ftp://luasocket:wrong@localhost/index.html;type=a", index) 106err = socket.ftp.put("ftp://luasocket:wrong@localhost/index.html;type=a", index)
107print(err)
104check(err, err) 108check(err, err)
105 109
106write("testing wrong file: ") 110io.write("testing wrong file: ")
107back, err = FTP.get("ftp://localhost/index.wrong.html;type=a") 111back, err = socket.ftp.get("ftp://localhost/index.wrong.html;type=a")
108check(err, err) 112check(err, err)
109 113
110print("passed all tests") 114print("passed all tests")
111print(format("done in %.2fs", _time() - t)) 115print(string.format("done in %.2fs", socket._time() - t))
diff --git a/test/httptest.lua b/test/httptest.lua
index 2941390..8b84f84 100644
--- a/test/httptest.lua
+++ b/test/httptest.lua
@@ -31,7 +31,7 @@ local check = function (v, e)
31end 31end
32 32
33local check_request = function(request, expect, ignore) 33local check_request = function(request, expect, ignore)
34 local response = http.request(request) 34 local response = socket.http.request(request)
35 for i,v in response do 35 for i,v in response do
36 if not ignore[i] then 36 if not ignore[i] then
37 if v ~= expect[i] then %fail(i .. " differs!") end 37 if v ~= expect[i] then %fail(i .. " differs!") end
@@ -56,13 +56,13 @@ index = readfile("test/index.html")
56 56
57io.write("testing request uri correctness: ") 57io.write("testing request uri correctness: ")
58local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string" 58local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string"
59local back = http.get("http://" .. HOST .. forth) 59local back = socket.http.get("http://" .. HOST .. forth)
60if similar(back, forth) then print("ok") 60if similar(back, forth) then print("ok")
61else fail("failed!") end 61else fail("failed!") end
62 62
63io.write("testing query string correctness: ") 63io.write("testing query string correctness: ")
64forth = "this+is+the+query+string" 64forth = "this+is+the+query+string"
65back = http.get("http://" .. HOST .. cgiprefix .. "/query-string?" .. forth) 65back = socket.http.get("http://" .. HOST .. cgiprefix .. "/query-string?" .. forth)
66if similar(back, forth) then print("ok") 66if similar(back, forth) then print("ok")
67else fail("failed!") end 67else fail("failed!") end
68 68
@@ -178,7 +178,7 @@ io.write("testing manual basic auth: ")
178request = { 178request = {
179 url = "http://" .. HOST .. prefix .. "/auth/index.html", 179 url = "http://" .. HOST .. prefix .. "/auth/index.html",
180 headers = { 180 headers = {
181 authorization = "Basic " .. Code.base64("luasocket:password") 181 authorization = "Basic " .. socket.code.base64("luasocket:password")
182 } 182 }
183} 183}
184expect = { 184expect = {
@@ -279,11 +279,11 @@ check_request(request, expect, ignore)
279 279
280local body 280local body
281io.write("testing simple get function: ") 281io.write("testing simple get function: ")
282body = http.get("http://" .. HOST .. prefix .. "/index.html") 282body = socket.http.get("http://" .. HOST .. prefix .. "/index.html")
283check(body == index) 283check(body == index)
284 284
285io.write("testing simple get function with table args: ") 285io.write("testing simple get function with table args: ")
286body = http.get { 286body = socket.http.get {
287 url = "http://really:wrong@" .. HOST .. prefix .. "/auth/index.html", 287 url = "http://really:wrong@" .. HOST .. prefix .. "/auth/index.html",
288 user = "luasocket", 288 user = "luasocket",
289 password = "password" 289 password = "password"
@@ -291,18 +291,18 @@ body = http.get {
291check(body == index) 291check(body == index)
292 292
293io.write("testing simple post function: ") 293io.write("testing simple post function: ")
294body = http.post("http://" .. HOST .. cgiprefix .. "/cat", index) 294body = socket.http.post("http://" .. HOST .. cgiprefix .. "/cat", index)
295check(body == index) 295check(body == index)
296 296
297io.write("testing simple post function with table args: ") 297io.write("testing simple post function with table args: ")
298body = http.post { 298body = socket.http.post {
299 url = "http://" .. HOST .. cgiprefix .. "/cat", 299 url = "http://" .. HOST .. cgiprefix .. "/cat",
300 body = index 300 body = index
301} 301}
302check(body == index) 302check(body == index)
303 303
304io.write("testing HEAD method: ") 304io.write("testing HEAD method: ")
305response = http.request { 305response = socket.http.request {
306 method = "HEAD", 306 method = "HEAD",
307 url = "http://www.tecgraf.puc-rio.br/~diego/" 307 url = "http://www.tecgraf.puc-rio.br/~diego/"
308} 308}
diff --git a/test/smtptest.lua b/test/smtptest.lua
index 6b01134..1bba27f 100644
--- a/test/smtptest.lua
+++ b/test/smtptest.lua
@@ -1,122 +1,130 @@
1local sent = {} 1local sent = {}
2 2
3local from = "luasock@tecgraf.puc-rio.br" 3local from = "diego@localhost"
4local server = "mail.tecgraf.puc-rio.br" 4local server = "localhost"
5local rcpt = "luasock@tecgraf.puc-rio.br" 5local rcpt = "luasocket@localhost"
6 6
7local name = "/var/spool/mail/luasock" 7local files = {
8 "/var/spool/mail/luasocket",
9 "/var/spool/mail/luasock1",
10 "/var/spool/mail/luasock2",
11 "/var/spool/mail/luasock3",
12}
8 13
9local t = _time() 14local t = socket._time()
10local err 15local err
11 16
12dofile("parsembox.lua") 17dofile("mbox.lua")
13local parse = parse 18local parse = mbox.parse
14dofile("noglobals.lua") 19dofile("noglobals.lua")
15 20
16local total = function() 21local total = function()
17 local t = 0 22 local t = 0
18 for i = 1, getn(%sent) do 23 for i = 1, table.getn(sent) do
19 t = t + %sent[i].count 24 t = t + sent[i].count
20 end 25 end
21 return t 26 return t
22end 27end
23 28
24local similar = function(s1, s2) 29local similar = function(s1, s2)
25 return strlower(gsub(s1, "%s", "")) == strlower(gsub(s2, "%s", "")) 30 return
26end 31 string.lower(string.gsub(s1, "%s", "")) ==
27 32 string.lower(string.gsub(s2, "%s", ""))
28local readfile = function(name)
29 local f = readfrom(name)
30 if not f then return nil end
31 local s = read("*a")
32 readfrom()
33 return s
34end
35
36local capture = function(cmd)
37 readfrom("| " .. cmd)
38 local s = read("*a")
39 readfrom()
40 return s
41end 33end
42 34
43local fail = function(s) 35local fail = function(s)
44 s = s or "failed!" 36 s = s or "failed!"
45 print(s) 37 print(s)
46 exit() 38 os.exit()
47end 39end
48 40
49local empty = function() 41local readfile = function(name)
50 local f = openfile(%name, "w") 42 local f = io.open(name, "r")
51 closefile(f) 43 if not f then
44 fail("unable to open file!")
45 return nil
46 end
47 local s = f:read("*a")
48 f:close()
49 return s
52end 50end
53 51
54local get = function() 52local empty = function()
55 return %readfile(%name) 53 for i,v in ipairs(files) do
54 local f = io.open(v, "w")
55 if not f then
56 fail("unable to open file!")
57 end
58 f:close()
59 end
56end 60end
57 61
58local list = function() 62local get = function()
59 return %capture("ls -l " .. %name) 63 s = ""
64 for i,v in ipairs(files) do
65 s = s .. "\n" .. readfile(v)
66 end
67 return s
60end 68end
61 69
62local check_headers = function(sent, got) 70local check_headers = function(sent, got)
63 sent = sent or {} 71 sent = sent or {}
64 got = got or {} 72 got = got or {}
65 for i,v in sent do 73 for i,v in sent do
66 if not %similar(v, got[i]) then %fail("header " .. v .. "failed!") end 74 if not similar(v, got[i]) then fail("header " .. v .. "failed!") end
67 end 75 end
68end 76end
69 77
70local check_body = function(sent, got) 78local check_body = function(sent, got)
71 sent = sent or "" 79 sent = sent or ""
72 got = got or "" 80 got = got or ""
73 if not %similar(sent, got) then %fail("bodies differ!") end 81 if not similar(sent, got) then fail("bodies differ!") end
74end 82end
75 83
76local check = function(sent, m) 84local check = function(sent, m)
77 write("checking ", m.headers.title, ": ") 85 io.write("checking ", m.headers.title, ": ")
78 for i = 1, getn(sent) do 86 for i = 1, table.getn(sent) do
79 local s = sent[i] 87 local s = sent[i]
80 if s.title == m.headers.title and s.count > 0 then 88 if s.title == m.headers.title and s.count > 0 then
81 %check_headers(s.headers, m.headers) 89 check_headers(s.headers, m.headers)
82 %check_body(s.body, m.body) 90 check_body(s.body, m.body)
83 s.count = s.count - 1 91 s.count = s.count - 1
84 print("ok") 92 print("ok")
85 return 93 return
86 end 94 end
87 end 95 end
88 %fail("not found") 96 fail("not found")
89end 97end
90 98
91local insert = function(sent, message) 99local insert = function(sent, message)
92 if type(message.rcpt) == "table" then 100 if type(message.rcpt) == "table" then
93 message.count = getn(message.rcpt) 101 message.count = table.getn(message.rcpt)
94 else message.count = 1 end 102 else message.count = 1 end
95 message.headers = message.headers or {} 103 message.headers = message.headers or {}
96 message.headers.title = message.title 104 message.headers.title = message.title
97 tinsert(sent, message) 105 table.insert(sent, message)
98end 106end
99 107
100local mark = function() 108local mark = function()
101 local time = _time() 109 local time = socket._time()
102 return { time = time } 110 return { time = time }
103end 111end
104 112
105local wait = function(sentinel, n) 113local wait = function(sentinel, n)
106 local to 114 local to
107 write("waiting for ", n, " messages: ") 115 io.write("waiting for ", n, " messages: ")
108 while 1 do 116 while 1 do
109 local mbox = %parse.mbox(%get()) 117 local mbox = parse(get())
110 if n == getn(mbox) then break end 118 if n == table.getn(mbox) then break end
111 if _time() - sentinel.time > 50 then 119 if socket._time() - sentinel.time > 50 then
112 to = 1 120 to = 1
113 break 121 break
114 end 122 end
115 _sleep(1) 123 socket._sleep(1)
116 write(".") 124 io.write(".")
117 flush(_STDOUT) 125 io.stdout:flush()
118 end 126 end
119 if to then %fail("timeout") 127 if to then fail("timeout")
120 else print("ok") end 128 else print("ok") end
121end 129end
122 130
@@ -129,16 +137,16 @@ Otherwise the mailer would
129think that the dot 137think that the dot
130. 138.
131is the end of the message 139is the end of the message
132and the remaining will cause 140and the remaining text would cause
133a lot of trouble. 141a lot of trouble.
134]] 142]]
135 143
136insert(sent, { 144insert(sent, {
137 from = from, 145 from = from,
138 rcpt = { 146 rcpt = {
139 "luasock2@tecgraf.puc-rio.br", 147 "luasocket@localhost",
140 "luasock", 148 "luasock3@dell-diego.cs.princeton.edu",
141 "luasock1" 149 "luasock1@dell-diego.cs.princeton.edu"
142 }, 150 },
143 body = "multiple rcpt body", 151 body = "multiple rcpt body",
144 title = "multiple rcpt", 152 title = "multiple rcpt",
@@ -147,8 +155,8 @@ insert(sent, {
147insert(sent, { 155insert(sent, {
148 from = from, 156 from = from,
149 rcpt = { 157 rcpt = {
150 "luasock2@tecgraf.puc-rio.br", 158 "luasock2@localhost",
151 "luasock", 159 "luasock3",
152 "luasock1" 160 "luasock1"
153 }, 161 },
154 headers = { 162 headers = {
@@ -199,9 +207,9 @@ insert(sent, {
199 title = "minimum message" 207 title = "minimum message"
200}) 208})
201 209
202write("testing host not found: ") 210io.write("testing host not found: ")
203local c, e = connect("wrong.host", 25) 211local c, e = socket.connect("wrong.host", 25)
204local err = SMTP.mail{ 212local err = socket.smtp.mail{
205 from = from, 213 from = from,
206 rcpt = rcpt, 214 rcpt = rcpt,
207 server = "wrong.host" 215 server = "wrong.host"
@@ -209,44 +217,43 @@ local err = SMTP.mail{
209if e ~= err then fail("wrong error message") 217if e ~= err then fail("wrong error message")
210else print("ok") end 218else print("ok") end
211 219
212write("testing invalid from: ") 220io.write("testing invalid from: ")
213local err = SMTP.mail{ 221local err = socket.smtp.mail{
214 from = ' " " (( _ * ', 222 from = ' " " (( _ * ',
215 rcpt = rcpt, 223 rcpt = rcpt,
216} 224}
217if not err then fail("wrong error message") 225if not err then fail("wrong error message")
218else print(err) end 226else print(err) end
219 227
220write("testing no rcpt: ") 228io.write("testing no rcpt: ")
221local err = SMTP.mail{ 229local err = socket.smtp.mail{
222 from = from, 230 from = from,
223} 231}
224if not err then fail("wrong error message") 232if not err then fail("wrong error message")
225else print(err) end 233else print(err) end
226 234
227write("clearing mailbox: ") 235io.write("clearing mailbox: ")
228empty() 236empty()
229print("ok") 237print("ok")
230 238
231write("sending messages: ") 239io.write("sending messages: ")
232for i = 1, getn(sent) do 240for i = 1, table.getn(sent) do
233 err = SMTP.mail(sent[i]) 241 err = socket.smtp.mail(sent[i])
234 if err then fail(err) end 242 if err then fail(err) end
235 write("+") 243 io.write("+")
236 flush(_STDOUT) 244 io.stdout:flush()
237end 245end
238print("ok") 246print("ok")
239 247
240wait(mark(), total()) 248wait(mark(), total())
241 249
242write("parsing mailbox: ") 250io.write("parsing mailbox: ")
243local mbox = parse.mbox(get()) 251local mbox = parse(get())
244print(getn(mbox) .. " messages found!") 252print(table.getn(mbox) .. " messages found!")
245 253
246for i = 1, getn(mbox) do 254for i = 1, table.getn(mbox) do
247 check(sent, mbox[i]) 255 check(sent, mbox[i])
248end 256end
249 257
250
251print("passed all tests") 258print("passed all tests")
252print(format("done in %.2fs", _time() - t)) 259print(string.format("done in %.2fs", socket._time() - t))
diff --git a/test/urltest.lua b/test/urltest.lua
index 8ca36fe..b97844d 100644
--- a/test/urltest.lua
+++ b/test/urltest.lua
@@ -1,5 +1,8 @@
1
2
3
1local check_build_url = function(parsed) 4local check_build_url = function(parsed)
2 local built = URL.build_url(parsed) 5 local built = socket.url.build(parsed)
3 if built ~= parsed.url then 6 if built ~= parsed.url then
4 print("built is different from expected") 7 print("built is different from expected")
5 print(built) 8 print(built)
@@ -9,7 +12,7 @@ local check_build_url = function(parsed)
9end 12end
10 13
11local check_protect = function(parsed, path, unsafe) 14local check_protect = function(parsed, path, unsafe)
12 local built = URL.build_path(parsed, unsafe) 15 local built = socket.url.build_path(parsed, unsafe)
13 if built ~= path then 16 if built ~= path then
14 print(built, path) 17 print(built, path)
15 print("path composition failed.") 18 print("path composition failed.")
@@ -18,9 +21,9 @@ local check_protect = function(parsed, path, unsafe)
18end 21end
19 22
20local check_invert = function(url) 23local check_invert = function(url)
21 local parsed = URL.parse_url(url) 24 local parsed = socket.url.parse(url)
22 parsed.path = URL.build_path(URL.parse_path(parsed.path)) 25 parsed.path = socket.url.build_path(socket.url.parse_path(parsed.path))
23 local rebuilt = URL.build_url(parsed) 26 local rebuilt = socket.url.build(parsed)
24 if rebuilt ~= url then 27 if rebuilt ~= url then
25 print(url, rebuilt) 28 print(url, rebuilt)
26 print("original and rebuilt are different") 29 print("original and rebuilt are different")
@@ -29,7 +32,7 @@ local check_invert = function(url)
29end 32end
30 33
31local check_parse_path = function(path, expect) 34local check_parse_path = function(path, expect)
32 local parsed = URL.parse_path(path) 35 local parsed = socket.url.parse_path(path)
33 for i = 1, math.max(table.getn(parsed), table.getn(expect)) do 36 for i = 1, math.max(table.getn(parsed), table.getn(expect)) do
34 if parsed[i] ~= expect[i] then 37 if parsed[i] ~= expect[i] then
35 print(path) 38 print(path)
@@ -48,7 +51,7 @@ local check_parse_path = function(path, expect)
48 print("is_absolute mismatch") 51 print("is_absolute mismatch")
49 exit() 52 exit()
50 end 53 end
51 local built = URL.build_path(expect) 54 local built = socket.url.build_path(expect)
52 if built ~= path then 55 if built ~= path then
53 print(built, path) 56 print(built, path)
54 print("path composition failed.") 57 print("path composition failed.")
@@ -57,7 +60,7 @@ local check_parse_path = function(path, expect)
57end 60end
58 61
59local check_absolute_url = function(base, relative, absolute) 62local check_absolute_url = function(base, relative, absolute)
60 local res = URL.absolute_url(base, relative) 63 local res = socket.url.absolute(base, relative)
61 if res ~= absolute then 64 if res ~= absolute then
62 write("absolute: In test for '", relative, "' expected '", 65 write("absolute: In test for '", relative, "' expected '",
63 absolute, "' but got '", res, "'\n") 66 absolute, "' but got '", res, "'\n")
@@ -68,7 +71,7 @@ end
68local check_parse_url = function(gaba) 71local check_parse_url = function(gaba)
69 local url = gaba.url 72 local url = gaba.url
70 gaba.url = nil 73 gaba.url = nil
71 local parsed = URL.parse_url(url) 74 local parsed = socket.url.parse(url)
72 for i, v in gaba do 75 for i, v in gaba do
73 if v ~= parsed[i] then 76 if v ~= parsed[i] then
74 write("parse: In test for '", url, "' expected ", i, " = '", 77 write("parse: In test for '", url, "' expected ", i, " = '",