Skip to content

Commit

Permalink
UrlFetchTitle: リダイレクト回数を表示するようにした
Browse files Browse the repository at this point in the history
fixed #22

Tiarra と同様の機能。
  • Loading branch information
ochaochaocha3 committed Apr 14, 2015
1 parent 59fd184 commit 778003b
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 10 deletions.
22 changes: 17 additions & 5 deletions lib/rgrb/plugin/url_fetch_title/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require 'active_support/core_ext/numeric/conversions'
require 'rgrb/version'
require 'rgrb/plugin/configurable_generator'
require 'rgrb/plugin/url_fetch_title/max_redirects_reached'

module RGRB
module Plugin
Expand All @@ -27,6 +28,7 @@ def configure(config_data)
@no_ssl_verify = config_data['NoSSLVerify'] || []
@open_timeout = config_data['OpenTimeout'] || 5
@read_timeout = config_data['ReadTimeout'] || 5
@max_redirects = config_data['MaxRedirects'] || 10
@reply_prefix = config_data['ReplyPrefix'] || 'Fetch title: '
@reply_suffix = config_data['ReplySuffix'] || ''
@user_agent = (
Expand All @@ -45,21 +47,25 @@ def configure(config_data)
#
# @todo 証明書チェックの省略ができるようにする
# (しかし、それは必要な機能か?)。
# @todo リダイレクト回数を数え、表示できるようにする。
#
# @param [String] url タイトルを取得するページのURL
# @return [String] 取得したタイトル、メタ情報
def fetch_title(url)
body =
begin
# TODO: リダイレクト回数のカウントで n_redirects を使う
headers, n_redirects = http_head(url)
content_type = headers[:content_type].split(';').first

case content_type
when 'text/html', 'application/xhtml+xml'
title = extract_title(http_get(url))
title.empty? ? '(タイトルなし)' : title
title_text = title.empty? ? '(タイトルなし)' : title

if n_redirects > 0
"#{title_text} [リダイレクト回数: #{n_redirects}]"
else
title_text
end
else
"(#{extract_content_data(headers).join('; ')})"
end
Expand Down Expand Up @@ -92,7 +98,7 @@ def fetch_error_to_message(error)

"HTTP #{http_code} #{reason_phrase}"
when RestClient::SSLCertificateNotVerified
"不正なSSL証明書"
'不正なSSL証明書'
else
error.message
end
Expand All @@ -106,16 +112,22 @@ def fetch_error_to_message(error)
# @return [Array<Hash, Integer>] HTTP 200 OK のとき、HTTP
# ヘッダとリダイレクト回数の配列
def http_head(url, n_redirects = 0)
fail(
MaxRedirectsReached, @max_redirects
) if n_redirects >= @max_redirects

RestClient::Request.execute(
method: :head,
url: url,
user_agent: @user_agent,
open_timeout: @open_timeout,
read_timeout: @read_timeout
read_timeout: @read_timeout,
) do |response, request, result, &block|
case response.code
when 200
[response.headers, n_redirects]
when 301, 302, 303, 307
http_head(response.headers[:location], n_redirects + 1)
else
response.return!(request, result, &block)
end
Expand Down
24 changes: 24 additions & 0 deletions lib/rgrb/plugin/url_fetch_title/max_redirects_reached.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# vim: fileencoding=utf-8

module RGRB
module Plugin
module UrlFetchTitle
# 最大リダイレクト回数に到達した場合のエラーを示すクラス
class MaxRedirectsReached < StandardError
# 新しい MaxRedirectsReached インスタンスを返す
# @param [String] table 表名
# @param [String] error_message エラーメッセージ
def initialize(max_redirects = nil, error_message = nil)
@max_redirects = max_redirects

if !error_message && @max_redirects
error_message =
"最大リダイレクト回数 (#{@max_redirects}) に到達しました"
end

super(error_message)
end
end
end
end
end
90 changes: 85 additions & 5 deletions spec/rgrb/plugin/url_fetch_title/generator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@
require 'rgrb/plugin/url_fetch_title/generator'

describe RGRB::Plugin::UrlFetchTitle::Generator do
let(:generator) { described_class.new }
let(:generator) { described_class.new.configure({}) }

describe '#configure (default)' do
let(:no_ssl_verify) { [] }
let(:open_timeout) { 5 }
let(:read_timeout) { 5 }
let(:max_redirects) { 10 }
let(:reply_prefix) { 'Fetch title: ' }
let(:reply_suffix) { '' }
let(:user_agent) do
"RGRB/#{RGRB::VERSION} (Creator's Network IRC bot)"
end

let(:config_data) { {} }
before { generator.configure(config_data) }

it '適切な既定値が設定される' do
expect(generator.instance_variable_get(:@no_ssl_verify)).
to eq(no_ssl_verify)
expect(generator.instance_variable_get(:@open_timeout)).
to eq(open_timeout)
expect(generator.instance_variable_get(:@read_timeout)).
to eq(read_timeout)
expect(generator.instance_variable_get(:@max_redirects)).
to eq(max_redirects)
expect(generator.instance_variable_get(:@reply_prefix)).
to eq(reply_prefix)
expect(generator.instance_variable_get(:@reply_suffix)).
Expand Down Expand Up @@ -68,7 +68,7 @@
'Content-Type' => 'text/html; charset=UTF-8',
}
}
stub_request(:head, url).to_return(p(response))
stub_request(:head, url).to_return(response)
stub_request(:get, url).
to_return(response.merge(body: body))
end
Expand All @@ -79,6 +79,86 @@
end
end

context 'HTML ファイル(リダイレクト)' do
let(:status_codes) { [301, 302, 303, 307, 200] }
let(:url) do
{
301 => 'http://www.cre.ne.jp/301',
302 => 'http://www.cre.ne.jp/302',
303 => 'http://www.cre.ne.jp/303',
307 => 'http://www.cre.ne.jp/307',
200 => 'http://www.cre.ne.jp/'
}
end

let(:html_path) do
File.expand_path('data/cre_ne_jp.html', File.dirname(__FILE__))
end

let(:body) { File.read(html_path) }

before do
response = {
302 => {
status: 302,
headers: {
'Location' => url[307]
}
},
307 => {
status: 307,
headers: {
'Location' => url[301]
}
},
301 => {
status: 301,
headers: {
'Location' => url[303]
}
},
303 => {
status: 303,
headers: {
'Location' => url[200]
}
},
200 => {
status: 200,
headers: {
'Content-Type' => 'text/html; charset=UTF-8',
}
}
}

status_codes.each do |status|
stub_request(:head, url[status]).to_return(response[status])

response_for_get =
(status == 200) ? response[200].merge(body: body) : response[status]
stub_request(:get, url[status]).to_return(response_for_get)
end
end

context '最大リダイレクト回数未満の場合' do
subject { generator.fetch_title(url[302]) }
it '<title> タグの内容とリダイレクト回数を含む' do
expect(subject).to eq(format['クリエイターズネットワーク [リダイレクト回数: 4]'])
end
end

context '最大リダイレクト回数に到達した場合' do
before do
generator.instance_variable_set(:@max_redirects, 3)
end

subject { generator.fetch_title(url[302]) }
it '最大リダイレクト回数に達したことを示すエラーメッセージが返る' do
expect(subject).to eq(format['!! 最大リダイレクト回数 (3) に到達しました'])
end
end
end

context 'HTML ファイル(タイトルなし)' do
let(:url) { 'http://example.net/empty_title' }
let(:html_path) do
Expand Down

0 comments on commit 778003b

Please sign in to comment.