Skip to content

Instantly share code, notes, and snippets.

@kotopes
Forked from mendelgusmao/gist:2356310
Last active December 11, 2015 23:58
Show Gist options
  • Save kotopes/4679855 to your computer and use it in GitHub Desktop.
Save kotopes/4679855 to your computer and use it in GitHub Desktop.
# based on http://uberblo.gs/2011/06/high-performance-url-shortening-with-redis-backed-nginx
# using code from http://stackoverflow.com/questions/3554315/lua-base-converter
# fixes: use adresses with args, and adresses to way out site. example: /shorten/www.bn.ru/?test=shorten
# "database scheme"
# database 5: id ~> url (use 0 is not good idea)
# database 1: id ~> hits
# database 2: id ~> [{referer|user_agent}]
# database 3: id ~> hits (when id is not found)
# database 4: id ~> [{referer|user_agent}] (when id is not found)
# database 5: key "count" storing the number of shortened urls; the id is generated by (this number + 1) converted to base 62
server {
location ~ ^/retrieve$ {
internal;
redis2_query select 5;
redis2_query get "ngx:shrt:$request_uri";
redis2_pass 127.0.0.1:6379;
}
location ~ ^/count$ {
internal;
redis2_query select 5;
redis2_query get "ngx:shrtcount";
redis2_pass 127.0.0.1:6379;
}
location ~ ^/history$ {
internal;
redis2_query select 1;
redis2_query incr "ngx:shrt:$request_uri";
redis2_query select 2;
redis2_query rpush "ngx:shrt:$request_uri" "$http_referer|$http_user_agent";
redis2_pass 127.0.0.1:6379;
}
location ~ ^/notfound$ {
internal;
redis2_query select 3;
redis2_query incr "ngx:shrt:$request_uri";
redis2_query select 4;
redis2_query rpush "ngx:shrt:$request_uri" "$http_referer|$http_user_agent";
redis2_pass 127.0.0.1:6379;
}
location ~ ^/store$ {
internal;
redis2_query select 5;
set_unescape_uri $id $arg_id;
set_unescape_uri $url $arg_url;
redis2_query set "ngx:shrt:$id" $url;
redis2_query select 5;
redis2_query incr "ngx:shrtcount";
redis2_pass 127.0.0.1:6379;
}
location ~ ^/shorten/(?<gurl>.*)$ {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
add_header Content-Type text/plain;
content_by_lua '
local parser = require "redis.parser";
local res = ngx.location.capture("/count");
local results, type = parser.parse_replies(res.body, 2);
basen = function(n, b)
n = math.floor(n);
if not b or b == 10 then return tostring(n) end
local digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
local t = {};
local sign = "";
if n < 0 then
sign = "-";
n = -n;
end
repeat
local d = (n % b) + 1;
n = math.floor(n / b);
table.insert(t, 1, digits:sub(d, d));
until n == 0
return sign .. table.concat(t, "");
end
if (results[2][1]) then
local id = basen(results[2][1] + 1, 62);
else
local id = basen(0, 62);
end
local in_args = ngx.req.get_uri_args();
local keys = {};
for key, val in pairs(in_args) do
table.insert(keys, key .. "=" .. val);
end
table.insert(keys, "from=" .. ngx.var.host);
local st_args = table.concat(keys, "&");
ngx.location.capture("/store",
{ args = { id = "/" .. tostring(id), url = ngx.encode_base64("http://" .. ngx.var.gurl .. "?" .. st_args) } }
);
ngx.say("original url: http://" .. ngx.var.gurl .. "?" .. st_args);
ngx.say(" shorted url: http://" .. ngx.var.host .. "/" .. id);
';
}
location / {
content_by_lua '
local parser = require "redis.parser";
local res = ngx.location.capture("/retrieve");
local href, type = parser.parse_reply(res.body);
if type == parser.ERROR_REPLY or href == nil then
ngx.location.capture("/notfound");
-- ngx.say("Not found");
ngx.exit(ngx.HTTP_NOT_FOUND);
else
ngx.location.capture("/history");
ngx.redirect(ngx.decode_base64(href));
end
';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment