ぴよログ

↓に移転したのでこっちは更新されません、多分。

OpenURIでhttpからhttpsのリダイレクトを一時的に許すgem作った

移転しました →

RubyではOpenURIを使うとウェブページを開くことができる。OpenURIでは引数に与えたURIプロトコルがHTTPリダイレクト先がHTTPSの場合、エラーが発生するという作りになっている。

ところで、HTTPからHTTPSへのリダイレクトは意外とたくさんある。

例えばGoogle短縮URL

http://goo.gl/84556T

リダイレクト先はここ。

https://github.com/xoyip/open_uri_allow_redirect

% irb
irb(main):001:0> require "open-uri"
=> true
irb(main):002:0> open "http://goo.gl/84556T"
RuntimeError: redirection forbidden: http://goo.gl/84556T -> https://github.com/xoyip/open_uri_allow_redirect
    from /Users/hiromasa/.rbenv/versions/2.1.0/lib/ruby/2.1.0/open-uri.rb:223:in `open_loop'
  from /Users/hiromasa/.rbenv/versions/2.1.0/lib/ruby/2.1.0/open-uri.rb:149:in `open_uri'
   from /Users/hiromasa/.rbenv/versions/2.1.0/lib/ruby/2.1.0/open-uri.rb:703:in `open'
  from /Users/hiromasa/.rbenv/versions/2.1.0/lib/ruby/2.1.0/open-uri.rb:34:in `open'
    from (irb):2
    from /Users/hiromasa/.rbenv/versions/2.1.0/bin/irb:11:in `<main>'
irb(main):003:0>

このようなケースでは、そのままのOpenURIは使えない。

open_uri_redirections

Rubyだから既存のクラスを拡張してしまえばよい。探してみるとOpenURIでHTTPSへのリダイレクトを許可するような拡張をしているgemがあった。

jaimeiniesta/open_uri_redirections

このgemにより、openメソッドallow_redirectionsというオプションを扱えるようになる。HTTPからHTTPSのリダイレクトやその逆のリダイレクトを許可するかどうかを呼び出し元が制御できるようになるというわけ。

require "open-uri"
require "open_uri_redirections"
open('http://github.com', :allow_redirections => :safe)
open('http://github.com', :allow_redirections => :all)

openの中で使われるredirectable?というメソッドを置き換えることによってこれを実現している。

このgemの問題点

openの呼び出しを自分で書くときはいいが、ライブラリなどの自分で手を加えにくいコードがopenを呼んでいる場合にはこのgemでは対応しきれない。

open_uri_allow_redirect作った

その問題を解決するために、少しばかり改変したgemを作った。

xoyip/open_uri_allow_redirect

このgemではopenの引数を使わず、OpenURI.allow_redirectに渡したブロック内のopen呼び出しは全てのリダイレクトを許可するという作りになっている。

こんな感じで使える。

require "open_uri_allow_redirect"

open("http://github.com") # => raises RuntimeError, redirected to https://github.com

OpenURI.allow_redirect do
  open("http://github.com") # => no error
end

ライブラリのコードがopenを呼んでいるときにも対応できる。

# in other library
module MyLibrary
  def use_open_method_internally(uri)
    open(uri)
  end
end

# main
require "open_uri_allow_redirect"
OpenURI.allow_redirect do
  MyLibrary.use_open_method_internally("http://github.com/") # => no error
end

いえい。