rubyのhttpclientでhttpsからhttpにredirectするとエラーになる

  • このエントリーをはてなブックマークに追加

httpclientでredirectの自動追従は次のオプションで出来る。

client = HTTPClient.new()
client.get('https://nghttp2.org/httpbin/redirect/2', :follow_redirect => true)

httpbinのredirectが404になるので、代わりのサイトで検証。

しかし、httpsからhttpへのredirectはBadResponseErrorになります。

client = HTTPClient.new()
client.get('https://nghttp2.org/httpbin/redirect-to?url=http%3A%2F%2Fexample.com', :follow_redirect => true)

ライブラリのコードはこんな感じでif https?(uri) && !https?(newuri)このコードで弾かれています。

def default_redirect_uri_callback(uri, res)
newuri = urify(res.header['location'][0])
if !http?(newuri) && !https?(newuri)
warn("#{newuri}: a relative URI in location header which is not recommended")
warn("'The field value consists of a single absolute URI' in HTTP spec")
newuri = uri + newuri
end
if https?(uri) && !https?(newuri)
raise BadResponseError.new("redirecting to non-https resource")
end
puts "redirect to: #{newuri}" if $DEBUG
newuri
end
https://github.com/nahi/httpclient/blob/master/lib/httpclient.rb#L722-L734

HTTPClient::BadResponseError (redirecting to non-https resource)

これはこれで正しいのですが、クローラーを書くときは無視したいことが多いです。そんな時は、clientのredirect_uri_callbackを自前のロジックに変更します。

client = HTTPClient.new()
client.redirect_uri_callback = lambda {|uri, res|
newuri = HTTPClient::Util.urify(res.header['location'][0])
if (newuri.scheme && (newuri.scheme.downcase == "https" || newuri.scheme.downcase == "http"))
else
newuri = uri + newuri
end
newuri
}

参考情報