Skip to content

Instantly share code, notes, and snippets.

@leite
Created September 8, 2012 18:46
Show Gist options
  • Save leite/3678525 to your computer and use it in GitHub Desktop.
Save leite/3678525 to your computer and use it in GitHub Desktop.
domain resolver service, a very simple, fast, low heap Lua script ... i wrote this to use together with gnutella2 cache/torrent tracker who lives in google appengine and doesnt have Inet class :(
--[[
----------------------------------------------------------------------------
"THE BEER-WARE LICENSE" (Revision 42):
<xxleite@gmail.com> wrote this file. As long as you retain this notice you
can do whatever you want with this stuff. If we meet some day, and you think
this stuff is worth it, you can buy me a beer in return
----------------------------------------------------------------------------
--]]
-- all necessery libs
local http = require 'http'
local coroutine = require 'coroutine'
local string = require 'string'
local table = require 'table'
local uv = require 'uv_native'
-- only local methods for fast addressing and low memory consumption
local gsub, find, match, format, sub, insert, each, resolve, create, resume =
string.gsub, string.find, string.match, string.format, string.sub, table.insert, table.foreach, uv.dnsGetAddrInfo, coroutine.create, coroutine.resume
-- clean memory
string, table, coroutine, uv = nil, nil, nil, nil
local port = 6969
-- retrieve domain only ... avoid any weird injection
local function get_domain(domain)
return match(domain, "[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?")
end
-- custom parser, luvit parse is not good
local function get_query(url)
if find(url, '?') == nil then return {} end
local results = {}
local parse_query = function(key, value)
if find(key, "%[%]") ~= nil then
key = gsub(key, '%[%]', '')
results[key] = results[key] and results[key] or {}
insert(results[key], value)
else
results[key] = value
end
end
gsub(url, "%/?%??([^&=]+)=?([^&=]*)&?", parse_query)
return results
end
-- resolve many domains it can using coroutines
local function resolve_domains_async(domains, finish_callback)
local i, results, total_domains, coroutine = 1, {}, #domains, nil
local callback = function(e, data, domain)
results[domain] = (e or not data) and '' or data[1]
total_domains = total_domains - 1
if total_domains == 0 then
finish_callback(results)
end
end
for i=1, total_domains do
coroutine = create(resolve)
resume(coroutine, domains[i], 2, function(err, data) callback(e, data, domains[i]) end)
end
end
-- main, where shit happens
local function main(req, res)
local body = ''
local function send(code, content_type)
res:writeHead(code, {
['Content-Type'] = content_type and content_type or 'text/plain',
['Content-Length'] = #body
})
res:finish(body)
return
end
local query = get_query(req.url)
if not query.domain then
body = [[<h2>You are not doing right</h2>
<p>this service only respond to domain/domain[] queries, e.g. </p>
<pre>?domain[]=google.com&domain[]=yahoo.com</pre><p>
and responses with json formated like this:</p>
<pre>{
"google" : "999.999.999.999",
"yahoo.com" : "999.999.999.999"
}</pre>]]
send(200, 'text/html')
else
local callback = function(resolved)
each(resolved, function(k, v)
body = body .. format('"%s":"%s",', k, v)
end)
body = "{".. sub(body, 1, -2) .."}"
send(200, 'application/json')
end
if type(query.domain)=='string' then
local t = {}
t[1] = query.domain
query.domain = t
end
resolve_domains_async(query.domain, callback)
end
end
-- horizon of events :D
http.createServer(main):listen(port)
print(format('server listening at http://localhost:%d', port))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment