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

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

例えばGoogleで短縮URL。

http://goo.gl/84556T

リダイレクト先はここ。

https://github.com/pi-chan/open_uri_allow_redirect

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

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

open_uri_redirections

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

jaimeiniesta/open_uri_redirections

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

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

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

このgemの問題点

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

open_uri_allow_redirect作った

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

pi-chan/open_uri_allow_redirect

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

こんな感じで使える。

1require "open_uri_allow_redirect"
2
3open("http://github.com") # => raises RuntimeError, redirected to https://github.com
4
5OpenURI.allow_redirect do
6  open("http://github.com") # => no error
7end

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

 1# in other library
 2module MyLibrary
 3  def use_open_method_internally(uri)
 4    open(uri)
 5  end
 6end
 7
 8# main
 9require "open_uri_allow_redirect"
10OpenURI.allow_redirect do
11  MyLibrary.use_open_method_internally("http://github.com/") # => no error
12end

いえい。