2011年4月29日金曜日

ruby 1.9.*でURL短縮サービスを作る

rubyでは、URL短縮サービスをWebサーバごと、しかも簡単に作ってしまうことができる。 その上、必要なライブラリはruby1.9.*標準添付ライブラリのみ。

ここでは、以下の機能を実装してみる。
  • /regのクエリにURLを渡しGETすると、元のURLとJSONで短縮したURLを返す
  • 短縮したURLはgdbmのデータベースに保存し、サーバ再起動後も参照できるものにする
  • 短縮にはMD5ハッシュを用いる(このままでは長いがとりあえず)

ソースコードは以下のとおり。
#!/usr/bin/env ruby1.9.2
#-*- coding: utf-8 -*-

require 'webrick'
require 'uri'
require 'gdbm'
require 'json'
require 'digest/md5'

# このサーバのURLを指定
BASE_URL = 'http://localhost:3939/'
# 短縮URLのデータベースファイル
db = GDBM.new('url.db')

# Webサーバを作成
sv = WEBrick::HTTPServer.new(:Port => URI.parse(BASE_URL).port)
trap(:INT){sv.stop}

# 短縮されたURLを受け取り、転送するServletを/にmount
sv.mount_proc('/'){|req, res|
  digest = req.path.gsub(/^\//, '')
  if digest =~ /^[0-9a-z]+$/i &&
      url = db[digest]
    res.set_redirect(WEBrick::HTTPStatus::Found, url)
  else
    res.body = 'unknown digest'
  end
}

# URLを短縮してJSONで返すServletを/regにmount
sv.mount_proc('/reg'){|req, res|
  url    = req.query['url']
  if url =~ URI.regexp && 
      URI.parse(url).scheme =~ /^(https?|ftp)$/
    digest = Digest::MD5.hexdigest(url)
    db[digest] = url
    res.body   = JSON.dump({'digest'=> digest,
                             'turl' => BASE_URL + digest,
                             'url'  => url})
  else
    res.body = 'bad url'
  end
}

# サーバを開始
sv.start
これだけでOK。
http://localhost:3939/add?url=http://hachune.net/http://hachune.net/を短縮URLサービスに登録し、返されたhttp://localhost:3939/fd9f9871bca66e8b49a919138982c9c1にアクセスすると、http://hachune.net/に転送される。
Apacheの用意も新規ライブラリの導入も要らず、とってもお手軽。
あとは、MD5のままだとどう見ても長すぎるので、可能な限り衝突が起きにくくかつ文字列の長さが短くなる関数を作る必要があるが、まぁその辺は適当に。

0 件のコメント:

コメントを投稿