mirror of
				https://github.com/lunarmodules/luasocket.git
				synced 2025-10-30 18:05:44 +01:00 
			
		
		
		
	Finish port to Lua 5. Everything is working fine.
Still doesn't work in Windows.
This commit is contained in:
		| @@ -1,13 +1,9 @@ | ||||
| dofile("../lua/http.lua") | ||||
| HTTP.TIMEOUT = 10 | ||||
| dofile("../lua/code.lua") | ||||
| dofile("../lua/url.lua") | ||||
| dofile("../lua/concat.lua") | ||||
| socket.http.TIMEOUT = 10 | ||||
|  | ||||
| cache = {} | ||||
|  | ||||
| function readfile(path) | ||||
| 	path = Code.unescape(path) | ||||
| 	path = socket.code.unescape(path) | ||||
| 	local file, error = openfile(path, "r") | ||||
| 	if file then  | ||||
|         local body = read(file, "*a") | ||||
| @@ -17,7 +13,7 @@ function readfile(path) | ||||
| end | ||||
|  | ||||
| function getstatus(url) | ||||
| 	local parsed = URL.parse_url(url, { scheme = "file" }) | ||||
| 	local parsed = socket.url.parse(url, { scheme = "file" }) | ||||
| 	if cache[url] then return cache[url].res end | ||||
| 	local res | ||||
|     if parsed.scheme == "http" then | ||||
| @@ -25,10 +21,10 @@ function getstatus(url) | ||||
|         local response = { body_cb = function(chunk, err)  | ||||
|             return nil | ||||
|         end } | ||||
| 		local blocksize = HTTP.BLOCKSIZE | ||||
| 		HTTP.BLOCKSIZE = 1 | ||||
|         response = HTTP.request_cb(request, response) | ||||
|         HTTP.BLOCKSIZE = blocksize | ||||
| 		local blocksize = socket.http.BLOCKSIZE | ||||
| 		socket.http.BLOCKSIZE = 1 | ||||
|         response = socket.http.request_cb(request, response) | ||||
|         socket.http.BLOCKSIZE = blocksize | ||||
|         if response.code == 200 then res = nil | ||||
|         else res = response.status or response.error end | ||||
|     elseif parsed.scheme == "file" then | ||||
| @@ -37,17 +33,17 @@ function getstatus(url) | ||||
|              closefile(file) | ||||
|              res = nil | ||||
|         else res = error end | ||||
|     else res = format("unhandled scheme '%s'", parsed.scheme) end | ||||
|     else res = string.format("unhandled scheme '%s'", parsed.scheme) end | ||||
|     cache[url] = { res = res } | ||||
| 	return res | ||||
| end | ||||
|  | ||||
| function retrieve(url) | ||||
| 	local parsed = URL.parse_url(url, { scheme = "file" }) | ||||
| 	local parsed = socket.url.parse(url, { scheme = "file" }) | ||||
|     local base, body, error | ||||
|     base = url | ||||
| 	if parsed.scheme == "http" then  | ||||
|         local response = HTTP.request{url = url} | ||||
|         local response = socket.http.request{url = url} | ||||
|         if response.code ~= 200 then  | ||||
|             error = response.status or response.error | ||||
|         else | ||||
| @@ -56,23 +52,23 @@ function retrieve(url) | ||||
|         end | ||||
|     elseif parsed.scheme == "file" then  | ||||
|         body, error = readfile(parsed.path)  | ||||
|     else error = format("unhandled scheme '%s'", parsed.scheme) end | ||||
|     else error = string.format("unhandled scheme '%s'", parsed.scheme) end | ||||
|     return base, body, error | ||||
| end | ||||
|  | ||||
| function getlinks(body, base) | ||||
|     -- get rid of comments | ||||
|     body = gsub(body, "%<%!%-%-.-%-%-%>", "") | ||||
|     body = string.gsub(body, "%<%!%-%-.-%-%-%>", "") | ||||
|     local links = {} | ||||
|     -- extract links | ||||
| 	gsub(body, '[Hh][Rr][Ee][Ff]%s*=%s*"([^"]*)"', function(href) | ||||
|         tinsert(%links, URL.absolute_url(%base, href)) | ||||
| 	string.gsub(body, '[Hh][Rr][Ee][Ff]%s*=%s*"([^"]*)"', function(href) | ||||
|         table.insert(links, socket.url.absolute(base, href)) | ||||
|     end) | ||||
| 	gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*'([^']*)'", function(href) | ||||
|         tinsert(%links, URL.absolute_url(%base, href)) | ||||
| 	string.gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*'([^']*)'", function(href) | ||||
|         table.insert(links, socket.url.absolute(base, href)) | ||||
|     end) | ||||
| 	gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*(%a+)", function(href) | ||||
|         tinsert(%links, URL.absolute_url(%base, href)) | ||||
| 	string.gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*(%a+)", function(href) | ||||
|         table.insert(links, socket.url.absolute(base, href)) | ||||
|     end) | ||||
|     return links | ||||
| end | ||||
| @@ -81,19 +77,19 @@ function checklinks(url) | ||||
| 	local base, body, error = retrieve(url) | ||||
|     if not body then print(error) return end | ||||
|     local links = getlinks(body, base) | ||||
|     for i = 1, getn(links) do | ||||
| 		write(_STDERR, "\t", links[i], "\n") | ||||
| 		local err = getstatus(links[i]) | ||||
| 		if err then write('\t', links[i], ": ", err, "\n") end | ||||
|     for _, l in ipairs(links) do | ||||
| 		io.stderr:write("\t", l, "\n") | ||||
| 		local err = getstatus(l) | ||||
| 		if err then io.stderr:write('\t', l, ": ", err, "\n") end | ||||
|     end | ||||
| end | ||||
|  | ||||
| arg = arg or {} | ||||
| if getn(arg) < 1 then | ||||
| 	write("Usage:\n  luasocket -f check-links.lua {<url>}\n") | ||||
| if table.getn(arg) < 1 then | ||||
| 	print("Usage:\n  luasocket check-links.lua {<url>}") | ||||
| 	exit() | ||||
| end | ||||
| for i = 1, getn(arg) do | ||||
| 	write("Checking ", arg[i], "\n") | ||||
| 	checklinks(URL.absolute_url("file:", arg[i])) | ||||
| for _, a in ipairs(arg) do | ||||
| 	print("Checking ", a) | ||||
| 	checklinks(socket.url.absolute("file:", a)) | ||||
| end | ||||
|   | ||||
							
								
								
									
										46
									
								
								etc/get.lua
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								etc/get.lua
									
									
									
									
									
								
							| @@ -13,8 +13,8 @@ function nicetime(s) | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	if l == "s" then return format("%2.0f%s", s, l) | ||||
| 	else return format("%5.2f%s", s, l) end | ||||
| 	if l == "s" then return string.format("%2.0f%s", s, l) | ||||
| 	else return string.format("%5.2f%s", s, l) end | ||||
| end | ||||
|  | ||||
| -- formats a number of bytes into human readable form | ||||
| @@ -32,21 +32,21 @@ function nicesize(b) | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	return format("%7.2f%2s", b, l) | ||||
| 	return string.format("%7.2f%2s", b, l) | ||||
| end | ||||
|  | ||||
| -- returns a string with the current state of the download | ||||
| function gauge(got, dt, size) | ||||
| 	local rate = got / dt | ||||
| 	if size and size >= 1 then | ||||
| 		return format("%s received, %s/s throughput, " .. | ||||
| 		return string.format("%s received, %s/s throughput, " .. | ||||
| 			"%.0f%% done, %s remaining",  | ||||
|             nicesize(got),   | ||||
| 			nicesize(rate),  | ||||
| 			100*got/size,  | ||||
| 			nicetime((size-got)/rate)) | ||||
| 	else  | ||||
| 		return format("%s received, %s/s throughput, %s elapsed",  | ||||
| 		return string.format("%s received, %s/s throughput, %s elapsed",  | ||||
| 			nicesize(got),  | ||||
| 			nicesize(rate), | ||||
| 			nicetime(dt)) | ||||
| @@ -57,22 +57,22 @@ end | ||||
| -- kind of copied from luasocket's manual callback examples | ||||
| function receive2disk(file, size) | ||||
| 	local aux = { | ||||
|         start = _time(), | ||||
|         start = socket._time(), | ||||
|         got = 0, | ||||
|         file = openfile(file, "wb"), | ||||
|         file = io.open(file, "wb"), | ||||
| 		size = size | ||||
|     } | ||||
|     local receive_cb = function(chunk, err) | ||||
|         local dt = _time() - %aux.start          -- elapsed time since start | ||||
|         local dt = socket._time() - %aux.start          -- elapsed time since start | ||||
|         if not chunk or chunk == "" then | ||||
| 			write("\n") | ||||
|             closefile(%aux.file) | ||||
| 			io.write("\n") | ||||
|             aux.file:close() | ||||
|             return | ||||
|         end | ||||
|         write(%aux.file, chunk) | ||||
|         %aux.got = %aux.got + strlen(chunk)      -- total bytes received | ||||
|         aux.file:write(chunk) | ||||
|         aux.got = aux.got + string.len(chunk)      -- total bytes received | ||||
|         if dt < 0.1 then return 1 end            -- not enough time for estimate | ||||
| 		write("\r", gauge(%aux.got, dt, %aux.size)) | ||||
| 		io.write("\r", gauge(aux.got, dt, aux.size)) | ||||
|         return 1 | ||||
|     end | ||||
| 	return receive_cb | ||||
| @@ -80,7 +80,7 @@ end | ||||
|  | ||||
| -- downloads a file using the ftp protocol | ||||
| function getbyftp(url, file) | ||||
|     local err = FTP.get_cb { | ||||
|     local err = socket.ftp.get_cb { | ||||
|         url = url, | ||||
|         content_cb = receive2disk(file), | ||||
|         type = "i" | ||||
| @@ -91,7 +91,7 @@ end | ||||
|  | ||||
| -- downloads a file using the http protocol | ||||
| function getbyhttp(url, file, size) | ||||
|     local response = HTTP.request_cb( | ||||
|     local response = socket.http.request_cb( | ||||
|         {url = url}, | ||||
| 		{body_cb = receive2disk(file, size)}  | ||||
|     ) | ||||
| @@ -101,7 +101,7 @@ end | ||||
|  | ||||
| -- determines the size of a http file | ||||
| function gethttpsize(url) | ||||
| 	local response = HTTP.request { | ||||
| 	local response = socket.http.request { | ||||
| 		method = "HEAD", | ||||
|  		url = url | ||||
| 	} | ||||
| @@ -113,11 +113,11 @@ end | ||||
| -- determines the scheme and the file name of a given url | ||||
| function getschemeandname(url, name) | ||||
| 	-- this is an heuristic to solve a common invalid url poblem | ||||
| 	if not strfind(url, "//") then url = "//" .. url end | ||||
| 	local parsed = URL.parse_url(url, {scheme = "http"}) | ||||
| 	if not string.find(url, "//") then url = "//" .. url end | ||||
| 	local parsed = socket.url.parse(url, {scheme = "http"}) | ||||
| 	if name then return parsed.scheme, name end | ||||
| 	local segment = URL.parse_path(parsed.path) | ||||
| 	name = segment[getn(segment)] | ||||
| 	local segment = socket.url.parse_path(parsed.path) | ||||
| 	name = segment[table.getn(segment)] | ||||
| 	if segment.is_directory then name = nil end | ||||
| 	return parsed.scheme, name | ||||
| end | ||||
| @@ -134,7 +134,7 @@ end | ||||
|  | ||||
| -- main program | ||||
| arg = arg or {} | ||||
| if getn(arg) < 1 then  | ||||
| 	write("Usage:\n  luasocket -f get.lua <remote-url> [<local-file>]\n") | ||||
| 	exit(1) | ||||
| if table.getn(arg) < 1 then  | ||||
| 	io.write("Usage:\n  luasocket get.lua <remote-url> [<local-file>]\n") | ||||
| 	os.exit(1) | ||||
| else get(arg[1], arg[2]) end | ||||
|   | ||||
							
								
								
									
										51
									
								
								src/ftp.lua
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								src/ftp.lua
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ | ||||
| ----------------------------------------------------------------------------- | ||||
|  | ||||
| local Public, Private = {}, {} | ||||
| FTP = Public | ||||
| socket.ftp = Public | ||||
|  | ||||
| ----------------------------------------------------------------------------- | ||||
| -- Program constants | ||||
| @@ -47,7 +47,7 @@ end | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.try_receive(...) | ||||
|     local sock = arg[1] | ||||
|     local data, err = call(sock.receive, arg) | ||||
|     local data, err = sock.receive(unpack(arg)) | ||||
|     if err then sock:close() end | ||||
|     return data, err | ||||
| end | ||||
| @@ -64,9 +64,9 @@ function Private.get_pasv(pasv) | ||||
| 	local a, b, c, d, p1, p2, _ | ||||
| 	local ip, port | ||||
| 	_,_, a, b, c, d, p1, p2 = | ||||
| 		strfind(pasv, "(%d*),(%d*),(%d*),(%d*),(%d*),(%d*)") | ||||
| 		string.find(pasv, "(%d*),(%d*),(%d*),(%d*),(%d*),(%d*)") | ||||
| 	if not (a and b and c and d and p1 and p2) then return nil, nil end | ||||
| 	ip = format("%d.%d.%d.%d", a, b, c, d) | ||||
| 	ip = string.format("%d.%d.%d.%d", a, b, c, d) | ||||
| 	port = tonumber(p1)*256 + tonumber(p2) | ||||
| 	return ip, port | ||||
| end | ||||
| @@ -100,13 +100,13 @@ function Private.get_answer(control) | ||||
| 	local line, err = Private.try_receive(control) | ||||
| 	local answer = line | ||||
| 	if err then return nil, err end | ||||
| 	_,_, code, sep = strfind(line, "^(%d%d%d)(.)") | ||||
| 	_,_, code, sep = string.find(line, "^(%d%d%d)(.)") | ||||
| 	if not code or not sep then return nil, answer end | ||||
| 	if sep == "-" then -- answer is multiline | ||||
| 		repeat  | ||||
| 			line, err = Private.try_receive(control) | ||||
| 			if err then return nil, err end | ||||
| 			_,_, lastcode, sep = strfind(line, "^(%d%d%d)(.)") | ||||
| 			_,_, lastcode, sep = string.find(line, "^(%d%d%d)(.)") | ||||
| 			answer = answer .. "\n" .. line | ||||
| 		until code == lastcode and sep == " " -- answer ends with same code | ||||
| 	end | ||||
| @@ -126,8 +126,8 @@ function Private.check_answer(control, success) | ||||
| 	local answer, code = Private.get_answer(control) | ||||
| 	if not answer then return nil, code end | ||||
| 	if type(success) ~= "table" then success = {success} end | ||||
| 	for i = 1, getn(success) do | ||||
| 		if code == success[i] then | ||||
| 	for _, s in ipairs(success) do | ||||
| 		if code == s then | ||||
| 			return code, answer | ||||
| 		end | ||||
| 	end | ||||
| @@ -213,13 +213,13 @@ function Private.port(control) | ||||
| 	local code, answer | ||||
| 	local server, ctl_ip | ||||
| 	ctl_ip, answer = control:getsockname() | ||||
| 	server, answer = bind(ctl_ip, 0) | ||||
| 	server, answer = socket.bind(ctl_ip, 0) | ||||
| 	server:timeout(Public.TIMEOUT) | ||||
| 	local ip, p, ph, pl | ||||
| 	ip, p = server:getsockname() | ||||
| 	pl = mod(p, 256) | ||||
| 	pl = math.mod(p, 256) | ||||
| 	ph = (p - pl)/256 | ||||
|     local arg = gsub(format("%s,%d,%d", ip, ph, pl), "%.", ",") | ||||
|     local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") | ||||
| 	code, answer = Private.command(control, "port", arg, {200}) | ||||
| 	if not code then  | ||||
| 		server:close() | ||||
| @@ -321,7 +321,7 @@ function Private.send_indirect(data, send_cb, chunk, size) | ||||
|             data:close() | ||||
|             return err | ||||
|         end | ||||
|         sent = sent + strlen(chunk) | ||||
|         sent = sent + string.len(chunk) | ||||
|         if sent >= size then break end | ||||
|         chunk, size = send_cb() | ||||
|     end | ||||
| @@ -374,7 +374,7 @@ end | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.change_type(control, params) | ||||
| 	local type, _ | ||||
| 	_, _, type = strfind(params or "", "type=(.)") | ||||
| 	_, _, type = string.find(params or "", "type=(.)") | ||||
| 	if type == "a" or type == "i" then  | ||||
| 		local code, err = Private.command(control, "type", type, {200}) | ||||
| 		if not code then return err end | ||||
| @@ -391,7 +391,7 @@ end | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.open(parsed) | ||||
| 	-- start control connection | ||||
| 	local control, err = connect(parsed.host, parsed.port) | ||||
| 	local control, err = socket.connect(parsed.host, parsed.port) | ||||
| 	if not control then return nil, err end | ||||
| 	-- make sure we don't block forever | ||||
| 	control:timeout(Public.TIMEOUT) | ||||
| @@ -423,7 +423,7 @@ end | ||||
| --   err: error message if any | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.change_dir(control, segment) | ||||
| 	local n = getn(segment) | ||||
|     local n = table.getn(segment) | ||||
| 	for i = 1, n-1 do | ||||
| 		local code, answer = Private.cwd(control, segment[i]) | ||||
| 		if not code then return answer end | ||||
| @@ -443,7 +443,7 @@ end | ||||
| function Private.upload(control, request, segment) | ||||
| 	local code, name, content_cb | ||||
| 	-- get remote file name | ||||
| 	name = segment[getn(segment)] | ||||
| 	name = segment[table.getn(segment)] | ||||
| 	if not name then  | ||||
| 		control:close() | ||||
| 		return "Invalid file path"  | ||||
| @@ -472,7 +472,7 @@ function Private.download(control, request, segment) | ||||
| 	is_directory = segment.is_directory | ||||
| 	content_cb = request.content_cb | ||||
| 	-- get remote file name | ||||
| 	name = segment[getn(segment)] | ||||
| 	name = segment[table.getn(segment)] | ||||
| 	if not name and not is_directory then  | ||||
| 		control:close() | ||||
| 		return "Invalid file path"  | ||||
| @@ -498,7 +498,7 @@ end | ||||
| --   parsed: a table with parsed components | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.parse_url(request) | ||||
| 	local parsed = URL.parse_url(request.url, { | ||||
| 	local parsed = socket.url.parse(request.url, { | ||||
| 		host = "", | ||||
| 		user = "anonymous",  | ||||
| 		port = 21,  | ||||
| @@ -521,9 +521,10 @@ end | ||||
| -- Returns | ||||
| --   dirs: a table with parsed directory components | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.parse_path(parsed) | ||||
| 	local segment = URL.parse_path(parsed.path) | ||||
| 	segment.is_directory = segment.is_directory or (parsed.params == "type=d") | ||||
| function Private.parse_path(parsed_url) | ||||
| 	local segment = socket.url.parse_path(parsed_url.path) | ||||
| 	segment.is_directory = segment.is_directory or  | ||||
|         (parsed_url.params == "type=d") | ||||
| 	return segment | ||||
| end | ||||
|  | ||||
| @@ -560,7 +561,7 @@ end | ||||
| function Public.get_cb(request) | ||||
| 	local parsed = Private.parse_url(request) | ||||
| 	if parsed.scheme ~= "ftp" then  | ||||
| 		return format("unknown scheme '%s'", parsed.scheme) | ||||
| 		return string.format("unknown scheme '%s'", parsed.scheme) | ||||
| 	end | ||||
| 	local control, err = Private.open(parsed) | ||||
| 	if not control then return err end | ||||
| @@ -586,7 +587,7 @@ end | ||||
| function Public.put_cb(request) | ||||
| 	local parsed = Private.parse_url(request) | ||||
| 	if parsed.scheme ~= "ftp" then  | ||||
| 		return format("unknown scheme '%s'", parsed.scheme) | ||||
| 		return string.format("unknown scheme '%s'", parsed.scheme) | ||||
| 	end | ||||
| 	local control, err = Private.open(parsed) | ||||
| 	if not control then return err end | ||||
| @@ -612,7 +613,7 @@ end | ||||
| function Public.put(url_or_request, content) | ||||
| 	local request = Private.build_request(url_or_request) | ||||
| 	request.content_cb = function() | ||||
| 		return content, strlen(content) | ||||
| 		return content, string.len(content) | ||||
| 	end | ||||
| 	return Public.put_cb(request) | ||||
| end | ||||
| @@ -630,7 +631,7 @@ end | ||||
| --   err: error message in case of error, nil otherwise | ||||
| ----------------------------------------------------------------------------- | ||||
| function Public.get(url_or_request) | ||||
| 	local cat = Concat.create() | ||||
| 	local cat = socket.concat.create() | ||||
| 	local request = Private.build_request(url_or_request) | ||||
| 	request.content_cb = function(chunk, err) | ||||
| 		if chunk then cat:addstring(chunk) end | ||||
|   | ||||
							
								
								
									
										10
									
								
								src/http.lua
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/http.lua
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ | ||||
| ----------------------------------------------------------------------------- | ||||
|  | ||||
| local Public, Private = {}, {} | ||||
| http = Public | ||||
| socket.http = Public | ||||
|  | ||||
| ----------------------------------------------------------------------------- | ||||
| -- Program constants | ||||
| @@ -427,7 +427,7 @@ end | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.authorize(request, parsed, response) | ||||
|     request.headers["authorization"] = "Basic " ..  | ||||
|         Code.base64(parsed.user .. ":" .. parsed.password) | ||||
|         socket.code.base64(parsed.user .. ":" .. parsed.password) | ||||
|     local authorize = { | ||||
|         redirects = request.redirects, | ||||
|         method = request.method, | ||||
| @@ -471,7 +471,7 @@ function Private.redirect(request, response) | ||||
|         method = request.method, | ||||
|         -- the RFC says the redirect URL has to be absolute, but some | ||||
|         -- servers do not respect that  | ||||
|         url = URL.absolute_url(request.url, response.headers["location"]), | ||||
|         url = socket.url.absolute(request.url, response.headers["location"]), | ||||
|         body_cb = request.body_cb, | ||||
|         headers = request.headers | ||||
|     } | ||||
| @@ -535,7 +535,7 @@ end | ||||
| --     error: error message, or nil if successfull | ||||
| ----------------------------------------------------------------------------- | ||||
| function Public.request_cb(request, response) | ||||
|     local parsed = URL.parse_url(request.url, { | ||||
|     local parsed = socket.url.parse(request.url, { | ||||
|         host = "", | ||||
|         port = Public.PORT,  | ||||
|         path ="/", | ||||
| @@ -622,7 +622,7 @@ function Public.request(request) | ||||
|             return request.body, string.len(request.body)  | ||||
|         end | ||||
|     end | ||||
|     local cat = Concat.create() | ||||
|     local cat = socket.concat.create() | ||||
|     response.body_cb = function(chunk, err) | ||||
|         if chunk then cat:addstring(chunk) end | ||||
|         return 1 | ||||
|   | ||||
							
								
								
									
										42
									
								
								src/mbox.lua
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								src/mbox.lua
									
									
									
									
									
								
							| @@ -4,11 +4,11 @@ mbox = Public | ||||
|  | ||||
| function Public.split_message(message_s) | ||||
|     local message = {} | ||||
|     message_s = gsub(message_s, "\r\n", "\n") | ||||
| 	gsub(message_s, "^(.-\n)\n", function (h) %message.headers = h end) | ||||
| 	gsub(message_s, "^.-\n\n(.*)", function (b) %message.body = b end) | ||||
|     message_s = string.gsub(message_s, "\r\n", "\n") | ||||
| 	string.gsub(message_s, "^(.-\n)\n", function (h) %message.headers = h end) | ||||
| 	string.gsub(message_s, "^.-\n\n(.*)", function (b) %message.body = b end) | ||||
|     if not message.body then | ||||
| 	    gsub(message_s, "^\n(.*)", function (b) %message.body = b end) | ||||
| 	    string.gsub(message_s, "^\n(.*)", function (b) %message.body = b end) | ||||
|     end | ||||
|     if not message.headers and not message.body then  | ||||
|         message.headers = message_s | ||||
| @@ -18,26 +18,26 @@ end | ||||
|  | ||||
| function Public.split_headers(headers_s) | ||||
|     local headers = {} | ||||
|     headers_s = gsub(headers_s, "\r\n", "\n") | ||||
|     headers_s = gsub(headers_s, "\n[ ]+", " ") | ||||
|     gsub("\n" .. headers_s, "\n([^\n]+)", function (h) tinsert(%headers, h) end) | ||||
|     headers_s = string.gsub(headers_s, "\r\n", "\n") | ||||
|     headers_s = string.gsub(headers_s, "\n[ ]+", " ") | ||||
|     string.gsub("\n" .. headers_s, "\n([^\n]+)", function (h) table.insert(%headers, h) end) | ||||
|     return headers | ||||
| end | ||||
|  | ||||
| function Public.parse_header(header_s) | ||||
|     header_s = gsub(header_s, "\n[ ]+", " ") | ||||
|     header_s = gsub(header_s, "\n+", "") | ||||
|     local _, __, name, value = strfind(header_s, "([^%s:]-):%s*(.*)") | ||||
|     header_s = string.gsub(header_s, "\n[ ]+", " ") | ||||
|     header_s = string.gsub(header_s, "\n+", "") | ||||
|     local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)") | ||||
|     return name, value | ||||
| end | ||||
|  | ||||
| function Public.parse_headers(headers_s) | ||||
|     local headers_t = %Public.split_headers(headers_s) | ||||
|     local headers = {} | ||||
|     for i = 1, getn(headers_t) do | ||||
|     for i = 1, table.getn(headers_t) do | ||||
|         local name, value = %Public.parse_header(headers_t[i]) | ||||
|         if name then | ||||
|             name = strlower(name) | ||||
|             name = string.lower(name) | ||||
|             if headers[name] then | ||||
|                 headers[name] = headers[name] .. ", " .. value | ||||
|             else headers[name] = value end | ||||
| @@ -47,34 +47,34 @@ function Public.parse_headers(headers_s) | ||||
| end | ||||
|  | ||||
| function Public.parse_from(from) | ||||
|     local _, __, name, address = strfind(from, "^%s*(.-)%s*%<(.-)%>") | ||||
|     local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>") | ||||
|     if not address then | ||||
|         _, __, address = strfind(from, "%s*(.+)%s*") | ||||
|         _, __, address = string.find(from, "%s*(.+)%s*") | ||||
|     end | ||||
|     name = name or "" | ||||
|     address = address or "" | ||||
|     if name == "" then name = address end | ||||
| 	name = gsub(name, '"', "") | ||||
| 	name = string.gsub(name, '"', "") | ||||
|     return name, address | ||||
| end | ||||
|  | ||||
| function Public.split_mbox(mbox_s) | ||||
| 	mbox = {} | ||||
| 	mbox_s = gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n" | ||||
| 	mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n" | ||||
| 	local nj, i, j = 1, 1, 1 | ||||
| 	while 1 do | ||||
| 		i, nj = strfind(mbox_s, "\n\nFrom .-\n", j) | ||||
| 		i, nj = string.find(mbox_s, "\n\nFrom .-\n", j) | ||||
| 		if not i then break end | ||||
| 		local message = strsub(mbox_s, j, i-1) | ||||
| 		tinsert(mbox, message) | ||||
| 		local message = string.sub(mbox_s, j, i-1) | ||||
| 		table.insert(mbox, message) | ||||
| 		j = nj+1 | ||||
| 	end | ||||
| 	return mbox | ||||
| end | ||||
|  | ||||
| function Public.parse_mbox(mbox_s) | ||||
| function Public.parse(mbox_s) | ||||
| 	local mbox = %Public.split_mbox(mbox_s) | ||||
| 	for i = 1, getn(mbox) do | ||||
| 	for i = 1, table.getn(mbox) do | ||||
| 		mbox[i] = %Public.parse_message(mbox[i]) | ||||
| 	end | ||||
| 	return mbox | ||||
|   | ||||
							
								
								
									
										21
									
								
								src/smtp.lua
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/smtp.lua
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ | ||||
| ----------------------------------------------------------------------------- | ||||
|  | ||||
| local Public, Private = {}, {} | ||||
| SMTP = Public | ||||
| socket.smtp = Public | ||||
|  | ||||
| ----------------------------------------------------------------------------- | ||||
| -- Program constants | ||||
| @@ -47,7 +47,7 @@ end | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.try_receive(...) | ||||
|     local sock = arg[1] | ||||
|     local data, err = call(sock.receive, arg) | ||||
|     local data, err = sock.receive(unpack(arg)) | ||||
|     if err then sock:close() end | ||||
|     return data, err | ||||
| end | ||||
| @@ -81,13 +81,13 @@ function Private.get_answer(control) | ||||
|     local line, err = Private.try_receive(control) | ||||
|     local answer = line | ||||
|     if err then return nil, err end | ||||
|     _,_, code, sep = strfind(line, "^(%d%d%d)(.)") | ||||
|     _,_, code, sep = string.find(line, "^(%d%d%d)(.)") | ||||
|     if not code or not sep then return nil, answer end | ||||
|     if sep == "-" then -- answer is multiline | ||||
|         repeat  | ||||
|             line, err = Private.try_receive(control) | ||||
|             if err then return nil, err end | ||||
|             _,_, lastcode, sep = strfind(line, "^(%d%d%d)(.)") | ||||
|             _,_, lastcode, sep = string.find(line, "^(%d%d%d)(.)") | ||||
|             answer = answer .. "\n" .. line | ||||
|         until code == lastcode and sep == " " -- answer ends with same code | ||||
|     end | ||||
| @@ -108,7 +108,7 @@ function Private.check_answer(control, success) | ||||
|     local answer, code = Private.get_answer(control) | ||||
|     if not answer then return nil, code end | ||||
|     if type(success) ~= "table" then success = {success} end | ||||
|     for i = 1, getn(success) do | ||||
|     for i = 1, table.getn(success) do | ||||
|         if code == success[i] then | ||||
|             return code, answer | ||||
|         end | ||||
| @@ -157,7 +157,7 @@ end | ||||
| --   answer: complete server reply or error message | ||||
| ----------------------------------------------------------------------------- | ||||
| function Private.send_mail(sock, sender) | ||||
|     local param = format("FROM:<%s>", sender or "") | ||||
|     local param = string.format("FROM:<%s>", sender or "") | ||||
|     local err = Private.send_command(sock, "MAIL", param) | ||||
|     if err then return nil, err end | ||||
|     return Private.check_answer(sock, 250) | ||||
| @@ -198,7 +198,7 @@ function Private.send_data(sock, headers, body) | ||||
|     local code, answer = Private.check_answer(sock, 354) | ||||
|     if not code then return nil, answer end | ||||
|     -- avoid premature end in message body | ||||
|     body = gsub(body or "", "\n%.", "\n%.%.") | ||||
|     body = string.gsub(body or "", "\n%.", "\n%.%.") | ||||
|     -- mark end of message body | ||||
|     body = body .. "\r\n.\r\n" | ||||
|     err = Private.send_headers(sock, headers) | ||||
| @@ -220,8 +220,9 @@ function Private.send_rcpt(sock, rcpt) | ||||
|     local err | ||||
| 	local code, answer = nil, "No recipient specified" | ||||
|     if type(rcpt) ~= "table" then rcpt = {rcpt} end | ||||
|     for i = 1, getn(rcpt) do | ||||
|         err = Private.send_command(sock, "RCPT", format("TO:<%s>", rcpt[i])) | ||||
|     for i = 1, table.getn(rcpt) do | ||||
|         err = Private.send_command(sock, "RCPT",  | ||||
|             string.format("TO:<%s>", rcpt[i])) | ||||
|         if err then return nil, err end | ||||
|         code, answer = Private.check_answer(sock, {250, 251}) | ||||
|         if not code then return code, answer end | ||||
| @@ -242,7 +243,7 @@ function Private.open(server) | ||||
| 	-- default server | ||||
| 	server = server or Public.SERVER | ||||
| 	-- connect to server and make sure we won't hang | ||||
|     local sock, err = connect(server, Public.PORT) | ||||
|     local sock, err = socket.connect(server, Public.PORT) | ||||
|     if not sock then return nil, err end | ||||
|     sock:timeout(Public.TIMEOUT) | ||||
|     -- initial server greeting | ||||
|   | ||||
							
								
								
									
										18
									
								
								src/url.lua
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/url.lua
									
									
									
									
									
								
							| @@ -8,7 +8,7 @@ | ||||
| ---------------------------------------------------------------------------- | ||||
|  | ||||
| local Public, Private = {}, {} | ||||
| URL = Public | ||||
| socket.url = Public | ||||
|  | ||||
| ----------------------------------------------------------------------------- | ||||
| -- Parses a url and returns a table with all its parts according to RFC 2396 | ||||
| @@ -28,7 +28,7 @@ URL = Public | ||||
| -- Obs: | ||||
| --   the leading '/' in {/<path>} is considered part of <path> | ||||
| ----------------------------------------------------------------------------- | ||||
| function Public.parse_url(url, default) | ||||
| function Public.parse(url, default) | ||||
|     -- initialize default parameters | ||||
|     local parsed = default or {} | ||||
|     -- empty url is parsed to nil | ||||
| @@ -70,7 +70,7 @@ end | ||||
| -- Returns | ||||
| --   a stringing with the corresponding URL | ||||
| ----------------------------------------------------------------------------- | ||||
| function Public.build_url(parsed) | ||||
| function Public.build(parsed) | ||||
|     local url = parsed.path or "" | ||||
|     if parsed.params then url = url .. ";" .. parsed.params end | ||||
|     if parsed.query then url = url .. "?" .. parsed.query end | ||||
| @@ -102,9 +102,9 @@ end | ||||
| -- Returns | ||||
| --   corresponding absolute url | ||||
| ----------------------------------------------------------------------------- | ||||
| function Public.absolute_url(base_url, relative_url) | ||||
|     local base = Public.parse_url(base_url) | ||||
|     local relative = Public.parse_url(relative_url) | ||||
| function Public.absolute(base_url, relative_url) | ||||
|     local base = Public.parse(base_url) | ||||
|     local relative = Public.parse(relative_url) | ||||
|     if not base then return relative_url | ||||
|     elseif not relative then return base_url | ||||
|     elseif relative.scheme then return relative_url | ||||
| @@ -124,7 +124,7 @@ function Public.absolute_url(base_url, relative_url) | ||||
|                 relative.path = Private.absolute_path(base.path,relative.path) | ||||
|             end | ||||
|         end | ||||
|         return Public.build_url(relative) | ||||
|         return Public.build(relative) | ||||
|     end | ||||
| end | ||||
|  | ||||
| @@ -141,7 +141,7 @@ function Public.parse_path(path) | ||||
| 	path = string.gsub(path, "%s", "") | ||||
| 	string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) | ||||
| 	for i = 1, table.getn(parsed) do | ||||
| 		parsed[i] = Code.unescape(parsed[i]) | ||||
| 		parsed[i] = socket.code.unescape(parsed[i]) | ||||
| 	end | ||||
| 	if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end | ||||
| 	if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end | ||||
| @@ -201,7 +201,7 @@ function Private.protect_segment(s) | ||||
| 	local segment_set = Private.segment_set | ||||
| 	return string.gsub(s, "(%W)", function (c)  | ||||
| 		if segment_set[c] then return c | ||||
| 		else return Code.escape(c) end | ||||
| 		else return socket.code.escape(c) end | ||||
| 	end) | ||||
| end | ||||
|  | ||||
|   | ||||
							
								
								
									
										118
									
								
								test/ftptest.lua
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								test/ftptest.lua
									
									
									
									
									
								
							| @@ -1,21 +1,24 @@ | ||||
| dofile("noglobals.lua") | ||||
|  | ||||
| local similar = function(s1, s2) | ||||
|     return strlower(gsub(s1, "%s", "")) == strlower(gsub(s2, "%s", "")) | ||||
| end | ||||
|  | ||||
| local capture = function(cmd) | ||||
| 	readfrom("| " .. cmd) | ||||
| 	local s = read("*a") | ||||
| 	readfrom() | ||||
| 	return s | ||||
|     return  | ||||
|     string.lower(string.gsub(s1, "%s", "")) ==  | ||||
|     string.lower(string.gsub(s2, "%s", "")) | ||||
| end | ||||
|  | ||||
| local readfile = function(name) | ||||
|     local f = readfrom(name) | ||||
| 	local f = io.open(name, "r") | ||||
| 	if not f then return nil end | ||||
|     local s = read("*a") | ||||
|     readfrom() | ||||
| 	local s = f:read("*a") | ||||
| 	f:close() | ||||
| 	return s | ||||
| end | ||||
|  | ||||
| local capture = function(cmd) | ||||
| 	local f = io.popen(cmd) | ||||
| 	if not f then return nil end | ||||
| 	local s = f:read("*a") | ||||
| 	f:close() | ||||
| 	return s | ||||
| end | ||||
|  | ||||
| @@ -23,7 +26,7 @@ local check = function(v, e, o) | ||||
| 	e = e or "failed!" | ||||
| 	o = o or "ok" | ||||
| 	if v then print(o) | ||||
| 	else print(e) exit() end | ||||
| 	else print(e) os.exit() end | ||||
| end | ||||
|  | ||||
| -- needs an account luasocket:password | ||||
| @@ -31,81 +34,82 @@ end | ||||
|  | ||||
| local index, err, saved, back, expected | ||||
|  | ||||
| local t = _time() | ||||
| local t = socket._time() | ||||
|  | ||||
| index = readfile("index.html") | ||||
| index = readfile("test/index.html") | ||||
|  | ||||
| write("testing file upload: ") | ||||
| remove("/var/ftp/dir1/index.up.html") | ||||
| err = FTP.put("ftp://localhost/dir1/index.up.html;type=i", index) | ||||
| saved = readfile("/var/ftp/dir1/index.up.html") | ||||
| io.write("testing wrong scheme: ") | ||||
| back, err = socket.ftp.get("wrong://banana.com/lixo") | ||||
| check(not back and err == "unknown scheme 'wrong'", err) | ||||
|  | ||||
| io.write("testing invalid url: ") | ||||
| back, err = socket.ftp.get("localhost/dir1/index.html;type=i") | ||||
| local c, e = socket.connect("", 21) | ||||
| check(not back and err == e, err) | ||||
|  | ||||
| io.write("testing anonymous file upload: ") | ||||
| os.remove("/var/ftp/pub/index.up.html") | ||||
| err = socket.ftp.put("ftp://localhost/pub/index.up.html;type=i", index) | ||||
| saved = readfile("/var/ftp/pub/index.up.html") | ||||
| check(not err and saved == index, err) | ||||
|  | ||||
| write("testing file download: ") | ||||
| back, err = FTP.get("ftp://localhost/dir1/index.up.html;type=i") | ||||
| io.write("testing anonymous file download: ") | ||||
| back, err = socket.ftp.get("ftp://localhost/pub/index.up.html;type=i") | ||||
| check(not err and back == index, err) | ||||
|  | ||||
| write("testing no directory changes: ") | ||||
| back, err = FTP.get("ftp://localhost/index.html;type=i") | ||||
| io.write("testing no directory changes: ") | ||||
| back, err = socket.ftp.get("ftp://localhost/index.html;type=i") | ||||
| check(not err and back == index, err) | ||||
|  | ||||
| write("testing multiple directory changes: ") | ||||
| back, err = FTP.get("ftp://localhost/dir1/dir2/dir3/dir4/dir5/dir6/index.html;type=i") | ||||
| io.write("testing multiple directory changes: ") | ||||
| back, err = socket.ftp.get("ftp://localhost/pub/dir1/dir2/dir3/dir4/dir5/index.html;type=i") | ||||
| check(not err and back == index, err) | ||||
|  | ||||
| write("testing authenticated upload: ") | ||||
| remove("/home/luasocket/index.up.html") | ||||
| err = FTP.put("ftp://luasocket:password@localhost/index.up.html;type=i", index) | ||||
| io.write("testing authenticated upload: ") | ||||
| os.remove("/home/luasocket/index.up.html") | ||||
| err = socket.ftp.put("ftp://luasocket:password@localhost/index.up.html;type=i", index) | ||||
| saved = readfile("/home/luasocket/index.up.html") | ||||
| check(not err and saved == index, err) | ||||
|  | ||||
| write("testing authenticated download: ") | ||||
| back, err = FTP.get("ftp://luasocket:password@localhost/index.up.html;type=i") | ||||
| io.write("testing authenticated download: ") | ||||
| back, err = socket.ftp.get("ftp://luasocket:password@localhost/index.up.html;type=i") | ||||
| check(not err and back == index, err) | ||||
|  | ||||
| write("testing weird-character translation: ") | ||||
| back, err = FTP.get("ftp://luasocket:password@localhost/%2fvar/ftp/dir1/index.html;type=i") | ||||
| io.write("testing weird-character translation: ") | ||||
| back, err = socket.ftp.get("ftp://luasocket:password@localhost/%2fvar/ftp/pub/index.html;type=i") | ||||
| check(not err and back == index, err) | ||||
|  | ||||
| write("testing parameter overriding: ") | ||||
| back, err = FTP.get { | ||||
| 	url = "//stupid:mistake@localhost/dir1/index.html", | ||||
| io.write("testing parameter overriding: ") | ||||
| back, err = socket.ftp.get { | ||||
| 	url = "//stupid:mistake@localhost/index.html", | ||||
| 	user = "luasocket", | ||||
| 	password = "password", | ||||
| 	type = "i" | ||||
| } | ||||
| check(not err and back == index, err) | ||||
|  | ||||
| write("testing wrong scheme: ") | ||||
| back, err = FTP.get("wrong://banana.com/lixo") | ||||
| check(not back and err == "unknown scheme 'wrong'", err) | ||||
|  | ||||
| write("testing invalid url: ") | ||||
| back, err = FTP.get("localhost/dir1/index.html;type=i") | ||||
| local c, e = connect("", 21) | ||||
| check(not back and err == e, err) | ||||
|  | ||||
| write("testing directory listing: ") | ||||
| expected = capture("ls -F /var/ftp/dir1 | grep -v /") | ||||
| back, err = FTP.get("ftp://localhost/dir1;type=d") | ||||
| check(similar(back, expected)) | ||||
|  | ||||
| write("testing home directory listing: ") | ||||
| io.write("testing home directory listing: ") | ||||
| expected = capture("ls -F /var/ftp | grep -v /") | ||||
| back, err = FTP.get("ftp://localhost/") | ||||
| back, err = socket.ftp.get("ftp://localhost/") | ||||
| check(back and similar(back, expected), nil, err) | ||||
|  | ||||
| write("testing upload denial: ") | ||||
| err = FTP.put("ftp://localhost/index.up.html;type=a", index) | ||||
| io.write("testing directory listing: ") | ||||
| expected = capture("ls -F /var/ftp/pub | grep -v /") | ||||
| back, err = socket.ftp.get("ftp://localhost/pub;type=d") | ||||
| check(similar(back, expected)) | ||||
|  | ||||
| io.write("testing upload denial: ") | ||||
| err = socket.ftp.put("ftp://localhost/index.up.html;type=a", index) | ||||
| check(err, err) | ||||
|  | ||||
| write("testing authentication failure: ") | ||||
| err = FTP.put("ftp://luasocket:wrong@localhost/index.html;type=a", index) | ||||
| io.write("testing authentication failure: ") | ||||
| err = socket.ftp.put("ftp://luasocket:wrong@localhost/index.html;type=a", index) | ||||
| print(err) | ||||
| check(err, err) | ||||
|  | ||||
| write("testing wrong file: ") | ||||
| back, err = FTP.get("ftp://localhost/index.wrong.html;type=a") | ||||
| io.write("testing wrong file: ") | ||||
| back, err = socket.ftp.get("ftp://localhost/index.wrong.html;type=a") | ||||
| check(err, err) | ||||
|  | ||||
| print("passed all tests") | ||||
| print(format("done in %.2fs", _time() - t)) | ||||
| print(string.format("done in %.2fs", socket._time() - t)) | ||||
|   | ||||
| @@ -31,7 +31,7 @@ local check = function (v, e) | ||||
| end | ||||
| 	 | ||||
| local check_request = function(request, expect, ignore) | ||||
| 	local response = http.request(request) | ||||
| 	local response = socket.http.request(request) | ||||
| 	for i,v in response do | ||||
| 		if not ignore[i] then | ||||
| 			if v ~= expect[i] then %fail(i .. " differs!") end | ||||
| @@ -56,13 +56,13 @@ index = readfile("test/index.html") | ||||
|  | ||||
| io.write("testing request uri correctness: ") | ||||
| local forth = cgiprefix .. "/request-uri?" .. "this+is+the+query+string" | ||||
| local back = http.get("http://" .. HOST .. forth) | ||||
| local back = socket.http.get("http://" .. HOST .. forth) | ||||
| if similar(back, forth) then print("ok") | ||||
| else fail("failed!") end | ||||
|  | ||||
| io.write("testing query string correctness: ") | ||||
| forth = "this+is+the+query+string" | ||||
| back = http.get("http://" .. HOST .. cgiprefix .. "/query-string?" .. forth) | ||||
| back = socket.http.get("http://" .. HOST .. cgiprefix .. "/query-string?" .. forth) | ||||
| if similar(back, forth) then print("ok") | ||||
| else fail("failed!") end | ||||
|  | ||||
| @@ -178,7 +178,7 @@ io.write("testing manual basic auth: ") | ||||
| request = { | ||||
| 	url = "http://" .. HOST .. prefix .. "/auth/index.html", | ||||
| 	headers = { | ||||
| 		authorization = "Basic " .. Code.base64("luasocket:password") | ||||
| 		authorization = "Basic " .. socket.code.base64("luasocket:password") | ||||
| 	} | ||||
| } | ||||
| expect = { | ||||
| @@ -279,11 +279,11 @@ check_request(request, expect, ignore) | ||||
|  | ||||
| local body | ||||
| io.write("testing simple get function: ") | ||||
| body = http.get("http://" .. HOST .. prefix .. "/index.html") | ||||
| body = socket.http.get("http://" .. HOST .. prefix .. "/index.html") | ||||
| check(body == index) | ||||
|  | ||||
| io.write("testing simple get function with table args: ") | ||||
| body = http.get { | ||||
| body = socket.http.get { | ||||
| 	url = "http://really:wrong@" .. HOST .. prefix .. "/auth/index.html", | ||||
| 	user = "luasocket", | ||||
| 	password = "password" | ||||
| @@ -291,18 +291,18 @@ body = http.get { | ||||
| check(body == index) | ||||
|  | ||||
| io.write("testing simple post function: ") | ||||
| body = http.post("http://" .. HOST .. cgiprefix .. "/cat", index) | ||||
| body = socket.http.post("http://" .. HOST .. cgiprefix .. "/cat", index) | ||||
| check(body == index) | ||||
|  | ||||
| io.write("testing simple post function with table args: ") | ||||
| body = http.post { | ||||
| body = socket.http.post { | ||||
| 	url = "http://" .. HOST .. cgiprefix .. "/cat", | ||||
| 	body = index | ||||
| } | ||||
| check(body == index) | ||||
|  | ||||
| io.write("testing HEAD method: ") | ||||
| response = http.request { | ||||
| response = socket.http.request { | ||||
|   method = "HEAD", | ||||
|   url = "http://www.tecgraf.puc-rio.br/~diego/" | ||||
| } | ||||
|   | ||||
| @@ -1,122 +1,130 @@ | ||||
| local sent = {} | ||||
|  | ||||
| local from = "luasock@tecgraf.puc-rio.br" | ||||
| local server = "mail.tecgraf.puc-rio.br" | ||||
| local rcpt = "luasock@tecgraf.puc-rio.br" | ||||
| local from = "diego@localhost" | ||||
| local server = "localhost" | ||||
| local rcpt = "luasocket@localhost" | ||||
|  | ||||
| local name = "/var/spool/mail/luasock" | ||||
| local files = { | ||||
|     "/var/spool/mail/luasocket", | ||||
|     "/var/spool/mail/luasock1", | ||||
|     "/var/spool/mail/luasock2", | ||||
|     "/var/spool/mail/luasock3", | ||||
| } | ||||
|  | ||||
| local t = _time() | ||||
| local t = socket._time() | ||||
| local err | ||||
|  | ||||
| dofile("parsembox.lua") | ||||
| local parse = parse | ||||
| dofile("mbox.lua") | ||||
| local parse = mbox.parse | ||||
| dofile("noglobals.lua") | ||||
|  | ||||
| local total = function() | ||||
| 	local t = 0 | ||||
| 	for i = 1, getn(%sent) do | ||||
| 		t = t + %sent[i].count | ||||
| 	for i = 1, table.getn(sent) do | ||||
| 		t = t + sent[i].count | ||||
| 	end | ||||
| 	return t | ||||
| end | ||||
|  | ||||
| local similar = function(s1, s2) | ||||
|     return strlower(gsub(s1, "%s", "")) == strlower(gsub(s2, "%s", "")) | ||||
| end | ||||
|  | ||||
| local readfile = function(name) | ||||
|     local f = readfrom(name) | ||||
|     if not f then return nil end | ||||
|     local s = read("*a") | ||||
|     readfrom() | ||||
|     return s | ||||
| end | ||||
|  | ||||
| local capture = function(cmd) | ||||
|     readfrom("| " .. cmd) | ||||
|     local s = read("*a") | ||||
|     readfrom() | ||||
|     return s | ||||
|     return  | ||||
|     string.lower(string.gsub(s1, "%s", "")) ==  | ||||
|     string.lower(string.gsub(s2, "%s", "")) | ||||
| end | ||||
|  | ||||
| local fail = function(s) | ||||
|     s = s or "failed!" | ||||
|     print(s) | ||||
|     exit() | ||||
|     os.exit() | ||||
| end | ||||
|  | ||||
| local readfile = function(name) | ||||
| 	local f = io.open(name, "r") | ||||
| 	if not f then  | ||||
|         fail("unable to open file!") | ||||
|         return nil  | ||||
|     end | ||||
| 	local s = f:read("*a") | ||||
| 	f:close() | ||||
| 	return s | ||||
| end | ||||
|  | ||||
| local empty = function() | ||||
|     local f = openfile(%name, "w") | ||||
|     closefile(f) | ||||
|     for i,v in ipairs(files) do | ||||
|         local f = io.open(v, "w") | ||||
|         if not f then  | ||||
|             fail("unable to open file!") | ||||
|         end | ||||
|         f:close() | ||||
|     end | ||||
| end | ||||
|  | ||||
| local get = function() | ||||
| 	return %readfile(%name) | ||||
| end | ||||
|  | ||||
| local list = function() | ||||
|     return %capture("ls -l " .. %name) | ||||
|     s = "" | ||||
|     for i,v in ipairs(files) do | ||||
| 	    s = s .. "\n" .. readfile(v) | ||||
|     end | ||||
|     return s | ||||
| end | ||||
|  | ||||
| local check_headers = function(sent, got) | ||||
|     sent = sent or {} | ||||
|     got = got or {} | ||||
|     for i,v in sent do | ||||
|         if not %similar(v, got[i]) then %fail("header " .. v .. "failed!") end | ||||
|         if not similar(v, got[i]) then fail("header " .. v .. "failed!") end | ||||
|     end | ||||
| end | ||||
|  | ||||
| local check_body = function(sent, got) | ||||
|     sent = sent or "" | ||||
|     got = got or "" | ||||
|     if not %similar(sent, got) then %fail("bodies differ!") end | ||||
|     if not similar(sent, got) then fail("bodies differ!") end | ||||
| end | ||||
|  | ||||
| local check = function(sent, m) | ||||
| 	write("checking ", m.headers.title, ": ") | ||||
| 	for i = 1, getn(sent) do | ||||
| 	io.write("checking ", m.headers.title, ": ") | ||||
| 	for i = 1, table.getn(sent) do | ||||
| 		local s = sent[i] | ||||
| 		if s.title == m.headers.title and s.count > 0 then | ||||
| 			%check_headers(s.headers, m.headers) | ||||
| 			%check_body(s.body, m.body) | ||||
| 			check_headers(s.headers, m.headers) | ||||
| 			check_body(s.body, m.body) | ||||
| 			s.count = s.count - 1 | ||||
| 			print("ok") | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| 	%fail("not found") | ||||
| 	fail("not found") | ||||
| end | ||||
|  | ||||
| local insert = function(sent, message) | ||||
| 	if type(message.rcpt) == "table" then | ||||
| 		message.count = getn(message.rcpt) | ||||
| 		message.count = table.getn(message.rcpt) | ||||
| 	else message.count = 1 end | ||||
| 	message.headers = message.headers or {} | ||||
| 	message.headers.title = message.title | ||||
| 	tinsert(sent, message) | ||||
| 	table.insert(sent, message) | ||||
| end | ||||
|  | ||||
| local mark = function() | ||||
| 	local time = _time() | ||||
| 	local time = socket._time() | ||||
|     return { time = time } | ||||
| end | ||||
|  | ||||
| local wait = function(sentinel, n) | ||||
|     local to | ||||
| 	write("waiting for ", n, " messages: ") | ||||
| 	io.write("waiting for ", n, " messages: ") | ||||
|     while 1 do | ||||
| 		local mbox = %parse.mbox(%get()) | ||||
| 		if n == getn(mbox) then break end | ||||
|         if _time() - sentinel.time > 50 then  | ||||
| 		local mbox = parse(get()) | ||||
| 		if n == table.getn(mbox) then break end | ||||
|         if socket._time() - sentinel.time > 50 then  | ||||
|             to = 1  | ||||
|             break | ||||
|         end | ||||
|         _sleep(1) | ||||
|         write(".") | ||||
|         flush(_STDOUT) | ||||
|         socket._sleep(1) | ||||
|         io.write(".") | ||||
|         io.stdout:flush() | ||||
|     end | ||||
| 	if to then %fail("timeout") | ||||
| 	if to then fail("timeout") | ||||
| 	else print("ok") end | ||||
| end | ||||
|  | ||||
| @@ -129,16 +137,16 @@ Otherwise the mailer would | ||||
| think that the dot | ||||
| . | ||||
| is the end of the message | ||||
| and the remaining will cause | ||||
| and the remaining text would cause | ||||
| a lot of trouble. | ||||
| ]] | ||||
|  | ||||
| insert(sent, { | ||||
|     from = from, | ||||
|     rcpt = { | ||||
| 		"luasock2@tecgraf.puc-rio.br", | ||||
| 		"luasock", | ||||
| 		"luasock1" | ||||
| 		"luasocket@localhost", | ||||
| 		"luasock3@dell-diego.cs.princeton.edu", | ||||
| 		"luasock1@dell-diego.cs.princeton.edu" | ||||
| 	}, | ||||
| 	body = "multiple rcpt body", | ||||
| 	title = "multiple rcpt", | ||||
| @@ -147,8 +155,8 @@ insert(sent, { | ||||
| insert(sent, { | ||||
|     from = from, | ||||
|     rcpt = { | ||||
| 		"luasock2@tecgraf.puc-rio.br", | ||||
| 		"luasock", | ||||
| 		"luasock2@localhost", | ||||
| 		"luasock3", | ||||
| 		"luasock1" | ||||
| 	}, | ||||
|     headers = { | ||||
| @@ -199,9 +207,9 @@ insert(sent, { | ||||
|     title = "minimum message" | ||||
| }) | ||||
|  | ||||
| write("testing host not found: ") | ||||
| local c, e = connect("wrong.host", 25) | ||||
| local err = SMTP.mail{ | ||||
| io.write("testing host not found: ") | ||||
| local c, e = socket.connect("wrong.host", 25) | ||||
| local err = socket.smtp.mail{ | ||||
| 	from = from, | ||||
| 	rcpt = rcpt, | ||||
| 	server = "wrong.host" | ||||
| @@ -209,44 +217,43 @@ local err = SMTP.mail{ | ||||
| if e ~= err then fail("wrong error message") | ||||
| else print("ok") end | ||||
|  | ||||
| write("testing invalid from: ") | ||||
| local err = SMTP.mail{ | ||||
| io.write("testing invalid from: ") | ||||
| local err = socket.smtp.mail{ | ||||
| 	from = ' " " (( _ * ',  | ||||
| 	rcpt = rcpt, | ||||
| } | ||||
| if not err then fail("wrong error message") | ||||
| else print(err) end | ||||
|  | ||||
| write("testing no rcpt: ") | ||||
| local err = SMTP.mail{ | ||||
| io.write("testing no rcpt: ") | ||||
| local err = socket.smtp.mail{ | ||||
| 	from = from,  | ||||
| } | ||||
| if not err then fail("wrong error message") | ||||
| else print(err) end | ||||
|  | ||||
| write("clearing mailbox: ") | ||||
| io.write("clearing mailbox: ") | ||||
| empty() | ||||
| print("ok") | ||||
|  | ||||
| write("sending messages: ") | ||||
| for i = 1, getn(sent) do | ||||
|     err = SMTP.mail(sent[i]) | ||||
| io.write("sending messages: ") | ||||
| for i = 1, table.getn(sent) do | ||||
|     err = socket.smtp.mail(sent[i]) | ||||
|     if err then fail(err) end | ||||
|     write("+") | ||||
|     flush(_STDOUT) | ||||
|     io.write("+") | ||||
|     io.stdout:flush() | ||||
| end | ||||
| print("ok") | ||||
|  | ||||
| wait(mark(), total()) | ||||
|  | ||||
| write("parsing mailbox: ") | ||||
| local mbox = parse.mbox(get()) | ||||
| print(getn(mbox) .. " messages found!") | ||||
| io.write("parsing mailbox: ") | ||||
| local mbox = parse(get()) | ||||
| print(table.getn(mbox) .. " messages found!") | ||||
|  | ||||
| for i = 1, getn(mbox) do | ||||
| for i = 1, table.getn(mbox) do | ||||
| 	check(sent, mbox[i]) | ||||
| end | ||||
|  | ||||
|  | ||||
| print("passed all tests") | ||||
| print(format("done in %.2fs", _time() - t)) | ||||
| print(string.format("done in %.2fs", socket._time() - t)) | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
|  | ||||
|  | ||||
|  | ||||
| local check_build_url = function(parsed) | ||||
| 	local built = URL.build_url(parsed) | ||||
| 	local built = socket.url.build(parsed) | ||||
|     if built ~= parsed.url then | ||||
| 	    print("built is different from expected") | ||||
| 		print(built) | ||||
| @@ -9,7 +12,7 @@ local check_build_url = function(parsed) | ||||
| end | ||||
|  | ||||
| local check_protect = function(parsed, path, unsafe) | ||||
| 	local built = URL.build_path(parsed, unsafe) | ||||
| 	local built = socket.url.build_path(parsed, unsafe) | ||||
| 	if built ~= path then | ||||
| 		print(built, path) | ||||
| 	    print("path composition failed.") | ||||
| @@ -18,9 +21,9 @@ local check_protect = function(parsed, path, unsafe) | ||||
| end | ||||
|  | ||||
| local check_invert = function(url) | ||||
| 	local parsed = URL.parse_url(url) | ||||
| 	parsed.path = URL.build_path(URL.parse_path(parsed.path)) | ||||
| 	local rebuilt = URL.build_url(parsed) | ||||
| 	local parsed = socket.url.parse(url) | ||||
| 	parsed.path = socket.url.build_path(socket.url.parse_path(parsed.path)) | ||||
| 	local rebuilt = socket.url.build(parsed) | ||||
| 	if rebuilt ~= url then | ||||
| 		print(url, rebuilt) | ||||
| 	    print("original and rebuilt are different") | ||||
| @@ -29,7 +32,7 @@ local check_invert = function(url) | ||||
| end | ||||
|  | ||||
| local check_parse_path = function(path, expect) | ||||
| 	local parsed = URL.parse_path(path) | ||||
| 	local parsed = socket.url.parse_path(path) | ||||
| 	for i = 1, math.max(table.getn(parsed), table.getn(expect)) do | ||||
| 		if parsed[i] ~= expect[i] then | ||||
| 			print(path) | ||||
| @@ -48,7 +51,7 @@ local check_parse_path = function(path, expect) | ||||
| 	    print("is_absolute mismatch") | ||||
| 		exit() | ||||
| 	end | ||||
| 	local built = URL.build_path(expect) | ||||
| 	local built = socket.url.build_path(expect) | ||||
| 	if built ~= path then | ||||
| 		print(built, path) | ||||
| 	    print("path composition failed.") | ||||
| @@ -57,7 +60,7 @@ local check_parse_path = function(path, expect) | ||||
| end | ||||
|  | ||||
| local check_absolute_url = function(base, relative, absolute) | ||||
| 	local res = URL.absolute_url(base, relative) | ||||
| 	local res = socket.url.absolute(base, relative) | ||||
| 	if res ~= absolute then  | ||||
| 		write("absolute: In test for '", relative, "' expected '",  | ||||
|             absolute, "' but got '", res, "'\n") | ||||
| @@ -68,7 +71,7 @@ end | ||||
| local check_parse_url = function(gaba) | ||||
| 	local url = gaba.url | ||||
| 	gaba.url = nil | ||||
| 	local parsed = URL.parse_url(url) | ||||
| 	local parsed = socket.url.parse(url) | ||||
| 	for i, v in gaba do | ||||
| 		if v ~= parsed[i] then | ||||
| 			write("parse: In test for '", url, "' expected ", i, " = '",  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user