ficon 0.5 → 0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ficon/version.rb +1 -1
- data/lib/ficon.rb +21 -0
- data/test/ficon_test.rb +112 -56
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95a5b1a8dba294c92d13f898bde371078e1927d67cb9e4af351608647f916d2f
|
4
|
+
data.tar.gz: 06f32b6dc310b8c7ea7dba49672f2ae85a8f1eaac890938414d27b031bf0808c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf4e5662d4b7322e559dd116524453025cd23d76407395c6da71ed7d15e8c8298f87ac97009c5ab52b551bfed6f1cc3bc61ba5f730e026340b09c9faef355161
|
7
|
+
data.tar.gz: df182b513fe144fca1d6a5eb6d5a2e58c4d92b69df063ce6df08a0567d7e7a83d9cef0c34a464778723f664e3650f95aee49b13814f1913133912ab81f83cc12
|
data/lib/ficon/version.rb
CHANGED
data/lib/ficon.rb
CHANGED
@@ -203,6 +203,27 @@ class Ficon
|
|
203
203
|
end
|
204
204
|
rescue => e
|
205
205
|
@url_status = classify_exception_status(e)
|
206
|
+
|
207
|
+
# If HTTP request failed and we're using HTTP, try HTTPS automatically
|
208
|
+
if uri.scheme == "http" &&
|
209
|
+
!uri.to_s.include?("://localhost") &&
|
210
|
+
!uri.host.match?(/^\d+\.\d+\.\d+\.\d+$/)
|
211
|
+
puts "HTTP request failed, trying HTTPS for #{uri}"
|
212
|
+
https_uri = uri.dup
|
213
|
+
https_uri.scheme = "https"
|
214
|
+
https_uri.port = 443 if https_uri.port == 80
|
215
|
+
|
216
|
+
begin
|
217
|
+
https_response = fetch_url(https_uri, redirect_limit)
|
218
|
+
if https_response
|
219
|
+
puts "HTTPS request succeeded, using HTTPS URL"
|
220
|
+
return https_response
|
221
|
+
end
|
222
|
+
rescue => https_error
|
223
|
+
puts "HTTPS fallback also failed: #{https_error.inspect}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
206
227
|
puts "Failed to fetch #{uri}: #{e.inspect}"
|
207
228
|
nil
|
208
229
|
end
|
data/test/ficon_test.rb
CHANGED
@@ -1,93 +1,92 @@
|
|
1
|
-
#require 'rubygems'
|
2
|
-
require
|
3
|
-
require
|
1
|
+
# require 'rubygems'
|
2
|
+
require "debug"
|
3
|
+
require "resolv"
|
4
4
|
|
5
5
|
require "minitest/autorun"
|
6
6
|
|
7
7
|
PathHere = File.dirname(__FILE__)
|
8
8
|
$LOAD_PATH.unshift File.join(PathHere, "..", "lib")
|
9
9
|
|
10
|
-
require
|
11
|
-
|
12
|
-
SiteTests = []
|
13
|
-
SiteTests << { html: %Q{<meta name="msapplication-TileImage" content="https://s.yimg.com/pw/images/favicon-msapplication-tileimage.png"/> }, value: 'https://s.yimg.com/pw/images/favicon-msapplication-tileimage.png' }
|
14
|
-
SiteTests << { html: %Q{<link rel="shortcut icon" type="image/ico" href="https://s.yimg.com/pw/favicon.ico"> }, value: 'https://s.yimg.com/pw/favicon.ico' }
|
15
|
-
SiteTests << { html: %Q{<link href="/apple-touch-icon.png" rel="apple-touch-icon-precomposed">}, value: 'https://site.com/apple-touch-icon.png' }
|
16
|
-
SiteTests << { html: %Q{<link rel="shortcut icon" href="/wp-content/themes/torrentfreakredux/assets/img/icons/favicon.png">}, value: 'https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/favicon.png' }
|
17
|
-
SiteTests << { html: %Q{<link rel="apple-touch-icon-precomposed" href="/wp-content/themes/torrentfreakredux/assets/img/icons/57.png">}, value: 'https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/57.png' }
|
18
|
-
SiteTests << { html: %Q{<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/wp-content/themes/torrentfreakredux/assets/img/icons/114.png">}, value: 'https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/114.png' }
|
19
|
-
SiteTests << { html: %Q{<link rel="apple-touch-icon-precomposed" sizes="72x72" href="/wp-content/themes/torrentfreakredux/assets/img/icons/72.png">}, value: 'https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/72.png' }
|
20
|
-
SiteTests << { html: %Q{<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/wp-content/themes/torrentfreakredux/assets/img/icons/144.png">}, value: 'https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/144.png' }
|
21
|
-
SiteTests << { html: %Q{<link rel="shortcut icon" href="/favicon.png">}, value: 'https://site.com/favicon.png' }
|
22
|
-
SiteTests << { html: %Q{<link rel="shortcut icon" href="favicon.ico" />}, value: 'https://site.com/favicon.ico' }
|
23
|
-
SiteTests << { html: %Q{<link rel="apple-touch-icon" href="/apple-touch-icon.png">}, value: 'https://site.com/apple-touch-icon.png' }
|
24
|
-
SiteTests << { html: %Q{<link rel="shortcut icon" href="http://example.com/myicon.ico" />}, value: 'http://example.com/myicon.ico'}
|
25
|
-
SiteTests << { html: %Q{<link rel="icon" href="http://example.com/image.ico" />}, value: 'http://example.com/image.ico' }
|
26
|
-
SiteTests << { html: %Q{<link rel="icon" type="image/vnd.microsoft.icon" href="http://example.com/image.ico" />}, value: 'http://example.com/image.ico' }
|
27
|
-
SiteTests << { html: %Q{<link rel="icon" type="image/png" href="http://example.com/image.png" />}, value: 'http://example.com/image.png' }
|
28
|
-
SiteTests << { html: %Q{<link rel="icon" type="image/gif" href="http://example.com/image.gif" />}, value: 'http://example.com/image.gif' }
|
29
|
-
SiteTests << { html: %Q{<link rel="icon" type="image/x-icon" href="http://example.com/image.ico"/>}, value: 'http://example.com/image.ico' }
|
30
|
-
SiteTests << { html: %Q{<link rel="shortcut icon" href="https://fbstatic-a.akamaihd.net/rsrc.php/yl/r/H3nktOa7ZMg.ico" />}, value: 'https://fbstatic-a.akamaihd.net/rsrc.php/yl/r/H3nktOa7ZMg.ico' }
|
31
|
-
SiteTests << { html: %Q{<link rel="icon" type="image/vnd.microsoft.icon" href="/viconline/img/favicon.ico?1393375504" />}, value: 'https://site.com/viconline/img/favicon.ico?1393375504' }
|
32
|
-
SiteTests << { html: %Q{<link rel="shortcut icon" type="image/x-icon" href="/viconline/img/favicon.ico?1393375504" />}, value: 'https://site.com/viconline/img/favicon.ico?1393375504' }
|
33
|
-
SiteTests << { html: %Q{<meta name="msapplication-TileImage" content="/win8-tile-144.png"/><meta name="msapplication-TileColor" content="#00aced"/>}, value: 'https://site.com/win8-tile-144.png' }
|
34
|
-
|
35
|
-
PageTests = []
|
36
|
-
PageTests << { html: %Q{<meta property="og:image" content="https://www.facebook.com/images/fb_icon_325x325.png" />}, value: 'https://www.facebook.com/images/fb_icon_325x325.png' }
|
10
|
+
require "ficon"
|
37
11
|
|
12
|
+
SiteTests = []
|
13
|
+
SiteTests << {html: %(<meta name="msapplication-TileImage" content="https://s.yimg.com/pw/images/favicon-msapplication-tileimage.png"/> ), value: "https://s.yimg.com/pw/images/favicon-msapplication-tileimage.png"}
|
14
|
+
SiteTests << {html: %(<link rel="shortcut icon" type="image/ico" href="https://s.yimg.com/pw/favicon.ico"> ), value: "https://s.yimg.com/pw/favicon.ico"}
|
15
|
+
SiteTests << {html: %(<link href="/apple-touch-icon.png" rel="apple-touch-icon-precomposed">), value: "https://site.com/apple-touch-icon.png"}
|
16
|
+
SiteTests << {html: %(<link rel="shortcut icon" href="/wp-content/themes/torrentfreakredux/assets/img/icons/favicon.png">), value: "https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/favicon.png"}
|
17
|
+
SiteTests << {html: %(<link rel="apple-touch-icon-precomposed" href="/wp-content/themes/torrentfreakredux/assets/img/icons/57.png">), value: "https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/57.png"}
|
18
|
+
SiteTests << {html: %(<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/wp-content/themes/torrentfreakredux/assets/img/icons/114.png">), value: "https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/114.png"}
|
19
|
+
SiteTests << {html: %(<link rel="apple-touch-icon-precomposed" sizes="72x72" href="/wp-content/themes/torrentfreakredux/assets/img/icons/72.png">), value: "https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/72.png"}
|
20
|
+
SiteTests << {html: %(<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/wp-content/themes/torrentfreakredux/assets/img/icons/144.png">), value: "https://site.com/wp-content/themes/torrentfreakredux/assets/img/icons/144.png"}
|
21
|
+
SiteTests << {html: %(<link rel="shortcut icon" href="/favicon.png">), value: "https://site.com/favicon.png"}
|
22
|
+
SiteTests << {html: %(<link rel="shortcut icon" href="favicon.ico" />), value: "https://site.com/favicon.ico"}
|
23
|
+
SiteTests << {html: %(<link rel="apple-touch-icon" href="/apple-touch-icon.png">), value: "https://site.com/apple-touch-icon.png"}
|
24
|
+
SiteTests << {html: %(<link rel="shortcut icon" href="http://example.com/myicon.ico" />), value: "http://example.com/myicon.ico"}
|
25
|
+
SiteTests << {html: %(<link rel="icon" href="http://example.com/image.ico" />), value: "http://example.com/image.ico"}
|
26
|
+
SiteTests << {html: %(<link rel="icon" type="image/vnd.microsoft.icon" href="http://example.com/image.ico" />), value: "http://example.com/image.ico"}
|
27
|
+
SiteTests << {html: %(<link rel="icon" type="image/png" href="http://example.com/image.png" />), value: "http://example.com/image.png"}
|
28
|
+
SiteTests << {html: %(<link rel="icon" type="image/gif" href="http://example.com/image.gif" />), value: "http://example.com/image.gif"}
|
29
|
+
SiteTests << {html: %(<link rel="icon" type="image/x-icon" href="http://example.com/image.ico"/>), value: "http://example.com/image.ico"}
|
30
|
+
SiteTests << {html: %(<link rel="shortcut icon" href="https://fbstatic-a.akamaihd.net/rsrc.php/yl/r/H3nktOa7ZMg.ico" />), value: "https://fbstatic-a.akamaihd.net/rsrc.php/yl/r/H3nktOa7ZMg.ico"}
|
31
|
+
SiteTests << {html: %(<link rel="icon" type="image/vnd.microsoft.icon" href="/viconline/img/favicon.ico?1393375504" />), value: "https://site.com/viconline/img/favicon.ico?1393375504"}
|
32
|
+
SiteTests << {html: %(<link rel="shortcut icon" type="image/x-icon" href="/viconline/img/favicon.ico?1393375504" />), value: "https://site.com/viconline/img/favicon.ico?1393375504"}
|
33
|
+
SiteTests << {html: %(<meta name="msapplication-TileImage" content="/win8-tile-144.png"/><meta name="msapplication-TileColor" content="#00aced"/>), value: "https://site.com/win8-tile-144.png"}
|
34
|
+
|
35
|
+
PageTests = []
|
36
|
+
PageTests << {html: %(<meta property="og:image" content="https://www.facebook.com/images/fb_icon_325x325.png" />), value: "https://www.facebook.com/images/fb_icon_325x325.png"}
|
38
37
|
|
39
38
|
class FiconTest < Minitest::Test
|
40
|
-
ENV[
|
39
|
+
ENV["FICON_DB"] = File.join(File.dirname(__FILE__), "test.db")
|
41
40
|
def test_html_chunks
|
42
41
|
SiteTests.each do |t|
|
43
|
-
result = Ficon.site_images(
|
44
|
-
assert result&.url == t[:value], "Seaching |#{t[:html]}| expected #{t[:value]}, got #{result}"
|
42
|
+
result = Ficon.site_images("https://site.com", Nokogiri::HTML(t[:html]))[0]
|
43
|
+
assert result&.url == t[:value], "Seaching |#{t[:html]}| expected #{t[:value]}, got #{result}"
|
45
44
|
end
|
46
45
|
PageTests.each do |t|
|
47
|
-
result = Ficon.page_images(
|
48
|
-
assert result&.url == t[:value], "Seaching |#{t[:html]}| expected #{t[:value]}, got #{result}"
|
46
|
+
result = Ficon.page_images("https://site.com", Nokogiri::HTML(t[:html]))[0]
|
47
|
+
assert result&.url == t[:value], "Seaching |#{t[:html]}| expected #{t[:value]}, got #{result}"
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
52
51
|
def test_tile_color_extraction
|
53
|
-
html = %
|
54
|
-
result = Ficon.site_images(
|
55
|
-
assert_equal
|
56
|
-
assert_equal
|
52
|
+
html = %(<meta name="msapplication-TileImage" content="/win8-tile-144.png"/><meta name="msapplication-TileColor" content="#00aced"/>)
|
53
|
+
result = Ficon.site_images("https://site.com", Nokogiri::HTML(html))[0]
|
54
|
+
assert_equal "https://site.com/win8-tile-144.png", result.url
|
55
|
+
assert_equal "#00aced", result.tile_color
|
57
56
|
end
|
58
57
|
|
59
58
|
def test_custom_user_agent
|
60
59
|
# Test default user agent
|
61
|
-
ficon_default = Ficon.new(
|
60
|
+
ficon_default = Ficon.new("https://example.com")
|
62
61
|
assert_match(/^FiconBot\/0\.\d+/, ficon_default.user_agent)
|
63
|
-
|
62
|
+
|
64
63
|
# Test custom user agent
|
65
|
-
custom_agent =
|
66
|
-
ficon_custom = Ficon.new(
|
64
|
+
custom_agent = "MyApp/1.0 (Custom Bot)"
|
65
|
+
ficon_custom = Ficon.new("https://example.com", user_agent: custom_agent)
|
67
66
|
assert_equal custom_agent, ficon_custom.user_agent
|
68
|
-
|
67
|
+
|
69
68
|
# Test user agent can be changed after initialization
|
70
|
-
ficon_custom.user_agent =
|
71
|
-
assert_equal
|
69
|
+
ficon_custom.user_agent = "Changed/2.0"
|
70
|
+
assert_equal "Changed/2.0", ficon_custom.user_agent
|
72
71
|
end
|
73
72
|
|
74
73
|
def test_response_status_classification
|
75
|
-
ficon = Ficon.new(
|
76
|
-
|
74
|
+
ficon = Ficon.new("https://example.com")
|
75
|
+
|
77
76
|
# Test ALIVE status (2xx)
|
78
77
|
assert_equal Ficon::ALIVE, ficon.classify_response_status(mock_response(200))
|
79
78
|
assert_equal Ficon::ALIVE, ficon.classify_response_status(mock_response(201))
|
80
79
|
assert_equal Ficon::ALIVE, ficon.classify_response_status(mock_response(299))
|
81
|
-
|
80
|
+
|
82
81
|
# Test DEAD status (404, 410)
|
83
82
|
assert_equal Ficon::DEAD, ficon.classify_response_status(mock_response(404))
|
84
83
|
assert_equal Ficon::DEAD, ficon.classify_response_status(mock_response(410))
|
85
|
-
|
84
|
+
|
86
85
|
# Test BLOCKED status (401, 403, 429)
|
87
86
|
assert_equal Ficon::BLOCKED, ficon.classify_response_status(mock_response(401))
|
88
87
|
assert_equal Ficon::BLOCKED, ficon.classify_response_status(mock_response(403))
|
89
88
|
assert_equal Ficon::BLOCKED, ficon.classify_response_status(mock_response(429))
|
90
|
-
|
89
|
+
|
91
90
|
# Test SICK status (5xx and others)
|
92
91
|
assert_equal Ficon::SICK, ficon.classify_response_status(mock_response(500))
|
93
92
|
assert_equal Ficon::SICK, ficon.classify_response_status(mock_response(502))
|
@@ -96,22 +95,79 @@ class FiconTest < Minitest::Test
|
|
96
95
|
end
|
97
96
|
|
98
97
|
def test_exception_status_classification
|
99
|
-
ficon = Ficon.new(
|
100
|
-
|
98
|
+
ficon = Ficon.new("https://example.com")
|
99
|
+
|
101
100
|
# Test DEAD status (DNS and resolution errors)
|
102
101
|
assert_equal Ficon::DEAD, ficon.classify_exception_status(SocketError.new)
|
103
102
|
assert_equal Ficon::DEAD, ficon.classify_exception_status(Resolv::ResolvError.new)
|
104
|
-
|
103
|
+
|
105
104
|
# Test SICK status (network and timeout errors)
|
106
105
|
assert_equal Ficon::SICK, ficon.classify_exception_status(Timeout::Error.new)
|
107
106
|
assert_equal Ficon::SICK, ficon.classify_exception_status(Errno::ECONNREFUSED.new)
|
108
107
|
assert_equal Ficon::SICK, ficon.classify_exception_status(OpenSSL::SSL::SSLError.new)
|
109
|
-
assert_equal Ficon::SICK, ficon.classify_exception_status(Net::HTTPError.new(
|
110
|
-
|
108
|
+
assert_equal Ficon::SICK, ficon.classify_exception_status(Net::HTTPError.new("error", nil))
|
109
|
+
|
111
110
|
# Test default to SICK for unknown exceptions
|
112
111
|
assert_equal Ficon::SICK, ficon.classify_exception_status(StandardError.new)
|
113
112
|
end
|
114
113
|
|
114
|
+
def test_http_to_https_fallback_conditions
|
115
|
+
# Test that localhost URLs are not converted to HTTPS
|
116
|
+
ficon_localhost = Ficon.allocate
|
117
|
+
uri_localhost = URI("http://localhost:3000/test")
|
118
|
+
|
119
|
+
# Mock the fetch_url method to simulate HTTP failure
|
120
|
+
def ficon_localhost.fetch_url(uri, redirect_limit = 5)
|
121
|
+
if uri.scheme == "http" && !uri.to_s.include?("://localhost") && !uri.host.match?(/^\d+\.\d+\.\d+\.\d+$/)
|
122
|
+
# This should not be reached for localhost
|
123
|
+
raise "Should not attempt HTTPS fallback for localhost"
|
124
|
+
end
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
# This should not raise an exception
|
129
|
+
result = ficon_localhost.send(:fetch_url, uri_localhost)
|
130
|
+
assert_nil result
|
131
|
+
|
132
|
+
# Test that IP addresses are not converted to HTTPS
|
133
|
+
ficon_ip = Ficon.allocate
|
134
|
+
uri_ip = URI("http://192.168.1.1/test")
|
135
|
+
|
136
|
+
def ficon_ip.fetch_url(uri, redirect_limit = 5)
|
137
|
+
if uri.scheme == "http" && !uri.to_s.include?("://localhost") && !uri.host.match?(/^\d+\.\d+\.\d+\.\d+$/)
|
138
|
+
# This should not be reached for IP addresses
|
139
|
+
raise "Should not attempt HTTPS fallback for IP addresses"
|
140
|
+
end
|
141
|
+
nil
|
142
|
+
end
|
143
|
+
|
144
|
+
# This should not raise an exception
|
145
|
+
result = ficon_ip.send(:fetch_url, uri_ip)
|
146
|
+
assert_nil result
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_https_port_conversion
|
150
|
+
# Test that port 80 is converted to 443 when switching to HTTPS
|
151
|
+
http_uri = URI("http://example.com:80/test")
|
152
|
+
assert_equal 80, http_uri.port
|
153
|
+
|
154
|
+
https_uri = http_uri.dup
|
155
|
+
https_uri.scheme = "https"
|
156
|
+
https_uri.port = 443 if https_uri.port == 80
|
157
|
+
|
158
|
+
assert_equal "https", https_uri.scheme
|
159
|
+
assert_equal 443, https_uri.port
|
160
|
+
|
161
|
+
# Test that custom ports are preserved
|
162
|
+
http_custom_uri = URI("http://example.com:8080/test")
|
163
|
+
https_custom_uri = http_custom_uri.dup
|
164
|
+
https_custom_uri.scheme = "https"
|
165
|
+
https_custom_uri.port = 443 if https_custom_uri.port == 80
|
166
|
+
|
167
|
+
assert_equal "https", https_custom_uri.scheme
|
168
|
+
assert_equal 8080, https_custom_uri.port # Should remain unchanged
|
169
|
+
end
|
170
|
+
|
115
171
|
private
|
116
172
|
|
117
173
|
def mock_response(code)
|