uriへのpingメソッド

正確にはpingではないけど、機能的には似てなくもないメソッド
引数にuriにHEADコマンドを投げて、open_timeout時間内に接続できればtrueを返す。
uriが有効(安全に読み込める)かどうかを知りたいときに便利。 同様の機能の既存のメソッドがあるかもしれないけど...

require 'net/http'
require 'uri'

# 接続が長時間ブロッキングされてしまわないか
def ping(uri,open_timeout,read_timeout=nil)
  uri = URI.parse(uri)
    
  http = Net::HTTP.new(uri.host, uri.port)
  http.open_timeout = open_timeout
  http.read_timeout = read_timeout unless read_timeout.nil?
  http.head(uri.path)
  return true
rescue Timeout::Error => ex
  return false
end

##

変種追加。

# リダイレクトを処理 + 20x以外のステータスコードの場合にもfalseを返す
# 成功した場合は、最終的に使われたURL(URI)も返す
def ping(uri,open_timeout,read_timeout=nil)
  uri_obj = URI.parse(uri)
  
  http = Net::HTTP.new(uri_obj.host, uri_obj.port)
  http.open_timeout = open_timeout
  http.read_timeout = read_timeout unless read_timeout.nil?
  
  # 2009/10/26: URI.queryを扱っていなかったバグを修正
  path  = uri_obj.path.empty? ? '/' : uri_obj.path
  path += "?"+uri_obj.query unless uri_obj.query.nil?

  # 注記: 2009/01/03: HEADコマンドに対応していないサーバもたまにあるので、確実性を重視するなら、以下はhttp.getに変えた方が良い
  res = http.head(path)    

  if res.code =~ /^30\d$/ && res['location']
    return ping(res['location'], open_timeout, read_timeout)
  elsif res.code =~ /^20\d$/
    return true, uri
  else
    return false
  end
rescue Timeout::Error => ex
  return false
end