Compare commits
10 Commits
ae5c02b7ed
...
eed9ee4583
| Author | SHA1 | Date | |
|---|---|---|---|
| eed9ee4583 | |||
| 3d9bdb1cab | |||
| fa9f0b785e | |||
| 4c36da46fe | |||
| c5d5c123a6 | |||
| 8826b1d672 | |||
| 5280a24f4b | |||
| 5de24e9fc4 | |||
| 33134c12f4 | |||
| 7c89900c70 |
@@ -1,5 +1,6 @@
|
|||||||
sudo: false
|
sudo: false
|
||||||
language: ruby
|
language: ruby
|
||||||
rvm:
|
rvm:
|
||||||
- 2.3.1
|
- 2.6.6
|
||||||
before_install: gem install bundler -v 1.16.2
|
cache: bundler
|
||||||
|
before_install: gem install bundler
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
[](http://travis-ci.org/5apps/manifique)
|
||||||
|
|
||||||
# Manifique
|
# Manifique
|
||||||
|
|
||||||
Manifique fetches metadata of Web applications, like e.g. name, description,
|
Manifique fetches metadata of Web applications, like e.g. name, description,
|
||||||
@@ -84,4 +86,4 @@ _TODO add information about dual/commercial licensing_
|
|||||||
|
|
||||||
Everyone interacting in this project’s codebase, issue trackers, and chat
|
Everyone interacting in this project’s codebase, issue trackers, and chat
|
||||||
rooms is expected to follow the [code of
|
rooms is expected to follow the [code of
|
||||||
conduct](https://github.com/skddc/manifique/blob/master/CODE_OF_CONDUCT.md).
|
conduct](https://github.com/5apps/manifique/blob/master/CODE_OF_CONDUCT.md).
|
||||||
|
|||||||
11
lib/manifique/errors.rb
Normal file
11
lib/manifique/errors.rb
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
module Manifique
|
||||||
|
class Error < ::StandardError
|
||||||
|
attr_reader :type, :url
|
||||||
|
|
||||||
|
def initialize(msg="Encountered an error", type="generic", url)
|
||||||
|
@type = type
|
||||||
|
@url = url
|
||||||
|
super(msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
require 'json'
|
require 'json'
|
||||||
require 'faraday'
|
require 'faraday'
|
||||||
require 'faraday_middleware'
|
require 'faraday_middleware'
|
||||||
require "nokogiri"
|
require 'nokogiri'
|
||||||
require 'manifique/metadata'
|
require 'manifique/metadata'
|
||||||
|
require 'manifique/errors'
|
||||||
|
|
||||||
module Manifique
|
module Manifique
|
||||||
class WebClient
|
class WebClient
|
||||||
@@ -103,7 +104,7 @@ module Manifique
|
|||||||
icon_links.each do |link|
|
icon_links.each do |link|
|
||||||
icon = {}
|
icon = {}
|
||||||
icon["src"] = link.attributes["href"].value rescue nil
|
icon["src"] = link.attributes["href"].value rescue nil
|
||||||
next if icon["src"].to_s.empty?
|
next unless is_adequate_src(icon["src"])
|
||||||
icon["sizes"] = link.attributes["sizes"].value rescue nil
|
icon["sizes"] = link.attributes["sizes"].value rescue nil
|
||||||
icon["type"] = link.attributes["type"].value rescue get_icon_type(icon["src"])
|
icon["type"] = link.attributes["type"].value rescue get_icon_type(icon["src"])
|
||||||
@metadata.icons.push icon
|
@metadata.icons.push icon
|
||||||
@@ -117,7 +118,7 @@ module Manifique
|
|||||||
icon_links.each do |link|
|
icon_links.each do |link|
|
||||||
icon = { "purpose" => "apple-touch-icon" }
|
icon = { "purpose" => "apple-touch-icon" }
|
||||||
icon["src"] = link.attributes["href"].value rescue nil
|
icon["src"] = link.attributes["href"].value rescue nil
|
||||||
next if icon["src"].to_s.empty?
|
next unless is_adequate_src(icon["src"])
|
||||||
icon["sizes"] = link.attributes["sizes"].value rescue nil
|
icon["sizes"] = link.attributes["sizes"].value rescue nil
|
||||||
icon["type"] = link.attributes["type"].value rescue get_icon_type(icon["src"])
|
icon["type"] = link.attributes["type"].value rescue get_icon_type(icon["src"])
|
||||||
@metadata.icons.push icon
|
@metadata.icons.push icon
|
||||||
@@ -130,7 +131,7 @@ module Manifique
|
|||||||
if mask_icon_link = @html.at_css("link[rel=mask-icon]")
|
if mask_icon_link = @html.at_css("link[rel=mask-icon]")
|
||||||
icon = { "purpose" => "mask-icon" }
|
icon = { "purpose" => "mask-icon" }
|
||||||
icon["src"] = mask_icon_link.attributes["href"].value rescue nil
|
icon["src"] = mask_icon_link.attributes["href"].value rescue nil
|
||||||
return if icon["src"].to_s.empty?
|
return unless is_adequate_src(icon["src"])
|
||||||
icon["type"] = link.attributes["type"].value rescue get_icon_type(icon["src"])
|
icon["type"] = link.attributes["type"].value rescue get_icon_type(icon["src"])
|
||||||
icon["color"] = mask_icon_link.attributes["color"].value rescue nil
|
icon["color"] = mask_icon_link.attributes["color"].value rescue nil
|
||||||
@metadata.icons.push icon
|
@metadata.icons.push icon
|
||||||
@@ -138,6 +139,14 @@ module Manifique
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_data_url?(src)
|
||||||
|
!!src.match(/^data:/)
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_adequate_src(src)
|
||||||
|
!src.to_s.empty? && !is_data_url?(src)
|
||||||
|
end
|
||||||
|
|
||||||
def get_icon_type(src)
|
def get_icon_type(src)
|
||||||
extension = src.match(/\.([a-zA-Z]+)$/)[1]
|
extension = src.match(/\.([a-zA-Z]+)$/)[1]
|
||||||
return "image/#{extension}"
|
return "image/#{extension}"
|
||||||
@@ -152,8 +161,10 @@ module Manifique
|
|||||||
if res.status < 400
|
if res.status < 400
|
||||||
res
|
res
|
||||||
else
|
else
|
||||||
raise "Could not fetch #{url} successfully (#{res.status})"
|
raise Manifique::Error.new "Failed with HTTP status #{res.status}", "http_#{res.status}", url
|
||||||
end
|
end
|
||||||
|
rescue Faraday::ConnectionFailed, Faraday::TimeoutError, Faraday::SSLError => e
|
||||||
|
raise Manifique::Error.new "Failed to connect", "connection_failed", url
|
||||||
end
|
end
|
||||||
|
|
||||||
def discover_web_manifest_url(html)
|
def discover_web_manifest_url(html)
|
||||||
@@ -161,6 +172,5 @@ module Manifique
|
|||||||
rescue
|
rescue
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
17
spec/fixtures/kommit.html
vendored
Normal file
17
spec/fixtures/kommit.html
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Kommit</title>
|
||||||
|
<meta name="description" content="Augment your memory" />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
||||||
|
<link rel="canonical" href="/" />
|
||||||
|
<link rel="alternate" hreflang="en" href="/en/" />
|
||||||
|
<link rel="apple-touch-icon" href="https://abcdefg.s3.amazonaws.com/public/icon.jpg">
|
||||||
|
</head>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -13,6 +13,13 @@ RSpec.describe Manifique::WebClient do
|
|||||||
|
|
||||||
stub_request(:get, "http://example.com/200_empty").
|
stub_request(:get, "http://example.com/200_empty").
|
||||||
to_return(body: "", status: 200, headers: {})
|
to_return(body: "", status: 200, headers: {})
|
||||||
|
|
||||||
|
stub_request(:get, "http://example.com/failed").
|
||||||
|
to_raise(Faraday::ConnectionFailed)
|
||||||
|
stub_request(:get, "http://example.com/timeout").
|
||||||
|
to_raise(Faraday::TimeoutError)
|
||||||
|
stub_request(:get, "http://example.com/ssl_error").
|
||||||
|
to_raise(Faraday::SSLError)
|
||||||
end
|
end
|
||||||
|
|
||||||
context "unsuccessful requests" do
|
context "unsuccessful requests" do
|
||||||
@@ -22,7 +29,12 @@ RSpec.describe Manifique::WebClient do
|
|||||||
it "raises an exception" do
|
it "raises an exception" do
|
||||||
expect {
|
expect {
|
||||||
client.send(:do_get_request, 'http://example.com/404')
|
client.send(:do_get_request, 'http://example.com/404')
|
||||||
}.to raise_error("Could not fetch http://example.com/404 successfully (404)")
|
}.to raise_error { |error|
|
||||||
|
expect(error).to be_a(Manifique::Error)
|
||||||
|
expect(error.message).to eq("Failed with HTTP status 404")
|
||||||
|
expect(error.type).to eq("http_404")
|
||||||
|
expect(error.url).to eq("http://example.com/404")
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -32,7 +44,39 @@ RSpec.describe Manifique::WebClient do
|
|||||||
it "raises an exception" do
|
it "raises an exception" do
|
||||||
expect {
|
expect {
|
||||||
client.send(:do_get_request, 'http://example.com/500')
|
client.send(:do_get_request, 'http://example.com/500')
|
||||||
}.to raise_error("Could not fetch http://example.com/500 successfully (500)")
|
}.to raise_error { |error|
|
||||||
|
expect(error).to be_a(Manifique::Error)
|
||||||
|
expect(error.message).to eq("Failed with HTTP status 500")
|
||||||
|
expect(error.type).to eq("http_500")
|
||||||
|
expect(error.url).to eq("http://example.com/500")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "failed connections" do
|
||||||
|
let(:client) { Manifique::WebClient.new }
|
||||||
|
|
||||||
|
it "raises an exception on connection failures" do
|
||||||
|
expect {
|
||||||
|
client.send(:do_get_request, 'http://example.com/failed')
|
||||||
|
}.to raise_error { |error|
|
||||||
|
expect(error).to be_a(Manifique::Error)
|
||||||
|
expect(error.message).to eq("Failed to connect")
|
||||||
|
expect(error.type).to eq("connection_failed")
|
||||||
|
expect(error.url).to eq("http://example.com/failed")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an exception on timeouts" do
|
||||||
|
expect {
|
||||||
|
client.send(:do_get_request, 'http://example.com/timeout')
|
||||||
|
}.to raise_error("Failed to connect")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an exception on SSL errors" do
|
||||||
|
expect {
|
||||||
|
client.send(:do_get_request, 'http://example.com/ssl_error')
|
||||||
|
}.to raise_error("Failed to connect")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -211,6 +255,38 @@ RSpec.describe Manifique::WebClient do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with data URL icons" do
|
||||||
|
before do
|
||||||
|
index_html = File.read(File.join(__dir__, "..", "fixtures", "kommit.html"));
|
||||||
|
stub_request(:get, "https://kosmos.social/").
|
||||||
|
to_return(body: index_html, status: 200, headers: {
|
||||||
|
"Content-Type": "text/html; charset=utf-8"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { web_client.fetch_metadata }
|
||||||
|
|
||||||
|
it "returns a metadata object" do
|
||||||
|
expect(subject).to be_kind_of(Manifique::Metadata)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "loads properties from parsed HTML" do
|
||||||
|
expect(subject.name).to eq("Kommit")
|
||||||
|
expect(subject.description).to eq("Augment your memory")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "ignores data URL icons" do
|
||||||
|
expect(subject.icons.length).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "loads icons from link[rel=apple-touch-icon] elements" do
|
||||||
|
apple_touch_icons = subject.icons.select{|i| i["purpose"] == "apple-touch-icon"}
|
||||||
|
expect(apple_touch_icons.length).to eq(1)
|
||||||
|
expect(apple_touch_icons.first["type"]).to eq("image/jpg")
|
||||||
|
expect(apple_touch_icons.first["sizes"]).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user