Ruby で書いたスクリプトが redirection forbidden という RuntimeError 例外を吐いてコケた。


/usr/lib/ruby/1.8/open-uri.rb:174:in `open_loop': redirection forbidden: http://twitpic.com/show/full/e38i7l -> https://d3j5vwomefv46c.cloudfront.net/photos/large/851962161.jpg?1399536621 (RuntimeError)
  from /usr/lib/ruby/1.8/open-uri.rb:132:in `open_uri'
  from /usr/lib/ruby/1.8/open-uri.rb:518:in `open'
  from /usr/lib/ruby/1.8/open-uri.rb:30:in `open'

どうやら、http から https へのリダイレクトが禁止されているらしい。

たとえば、仮にopen-uriがPUTをサポートしたとしたら、無条件に
untaintしてredirectするのはまずいですよね。
# RFC2616でもredirectはGET/HEADのみということになってますが。

open-uriの場合は、

unless OpenURI.redirectable?(uri, redirect)
raise "redirection forbidden: #{uri} -> #{redirect}"
end

でredirectが妥当かどうかをチェックしているので、何らかの危険性
があると判断されるようなredirectはここで蹴って、その後でuntaint
するのがよいのではないでしょうか。

[ruby-dev:26485] Re: $SAFE=1 の open-uri で redirect 時にエラー

OpenURI.redirectable? のソースコードはこのへん http://svn.ruby-lang.org/repos/ruby/tags/v1_8_7_358/lib/open-uri.rb にあるので該当箇所を見てみると、


def OpenURI.redirectable?(uri1, uri2) # :nodoc:
  # This test is intended to forbid a redirection from http://... to
  # file:///etc/passwd.
  # However this is ad hoc.  It should be extensible/configurable.
  uri1.scheme.downcase == uri2.scheme.downcase ||
  (/\A(?:http|ftp)\z/i =~ uri1.scheme && /\A(?:http|ftp)\z/i =~ uri2.scheme)
end

正規表現さっぱりわからん(;・∀・)

とりあえず、エラーになってしまうスクリプトは http -> https を https -> https に修正して対処できた。ふぅ。

もうちょっと探してみると、http から https へのリダイレクトをエラーにしないようにしてくれるライブラリがあった。

This gem applies a patch to OpenURI to optionally allow redirections from HTTP to HTTPS, or from HTTPS to HTTP.

jaimeiniesta/open_uri_redirections · GitHub

やっぱり、他にも困っている人がいたということで。

tags: ruby

Posted by NI-Lab. (@nilab)