diff --git a/lib/manifique/web_client.rb b/lib/manifique/web_client.rb index 9e52208..704168b 100644 --- a/lib/manifique/web_client.rb +++ b/lib/manifique/web_client.rb @@ -13,8 +13,25 @@ module Manifique end def fetch_web_manifest - do_get_request @url - # binding.pry + res = do_get_request @url + links = parse_http_link_header(res) + doc = Nokogiri::HTML(res.body) + manifest_url = discover_web_manifest_url(links, doc) + + unless manifest_url.match(/^https?\:\/\//) + # Link is just the manifest path, not an absolute URL + manifest_url = @url + manifest_url + end + + res = do_get_request manifest_url + + begin + manifest_data = JSON.parse(res.body) + rescue + manifest_data = false + end + + manifest_data end private @@ -31,5 +48,20 @@ module Manifique res end end + + def parse_http_link_header(response) + link_parser = Nitlink::Parser.new + link_parser.parse(response) + end + + def discover_web_manifest_url(links, doc) + # TODO implement/test link header discovery + # if url = links.by_rel('manifest').target.to_s or + if url = doc.at_css("link[rel=manifest]").attributes["href"].value + return url + else + raise "No Web App Manifest found on #{@url}" + end + end end end diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..013026c --- /dev/null +++ b/manifest.json @@ -0,0 +1 @@ +{"name":"kosmos.social","short_name":"kosmos.social","description":"A friendly place for tooting. Run by the Kosmos peeps.","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"}],"theme_color":"#282c37","background_color":"#191b22","display":"standalone","start_url":"/web/timelines/home","scope":"https://kosmos.social/","share_target":{"url_template":"share?title={title}\u0026text={text}\u0026url={url}"}} \ No newline at end of file diff --git a/spec/fixtures/mastodon-web-app-manifest.json b/spec/fixtures/mastodon-web-app-manifest.json new file mode 100644 index 0000000..8fa7253 --- /dev/null +++ b/spec/fixtures/mastodon-web-app-manifest.json @@ -0,0 +1,20 @@ +{ + "name": "kosmos.social", + "short_name": "kosmos.social", + "description": "A friendly place for tooting. Run by the Kosmos peeps.", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + } + ], + "theme_color": "#282c37", + "background_color": "#191b22", + "display": "standalone", + "start_url": "/web/timelines/home", + "scope": "https://kosmos.social/", + "share_target": { + "url_template": "share?title={title}&text={text}&url={url}" + } +} diff --git a/spec/fixtures/mastodon.html b/spec/fixtures/mastodon.html new file mode 100644 index 0000000..a2e3631 --- /dev/null +++ b/spec/fixtures/mastodon.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + kosmos.social + + + + + + + + + + + + + + + +
+ +
+ + diff --git a/spec/manifique/agent_spec.rb b/spec/manifique/agent_spec.rb index f217004..a2ec219 100644 --- a/spec/manifique/agent_spec.rb +++ b/spec/manifique/agent_spec.rb @@ -5,8 +5,8 @@ RSpec.describe Manifique::Agent do describe "URL validation" do context "with invalid URL" do it "raises an exception" do - expect { Manifique::Agent.new }.to raise_error - expect { Manifique::Agent.new(url: "htp://example.com") }.to raise_error + expect { Manifique::Agent.new }.to raise_error(RuntimeError) + expect { Manifique::Agent.new(url: "htp://example.com") }.to raise_error(RuntimeError) end end diff --git a/spec/manifique/web_client_spec.rb b/spec/manifique/web_client_spec.rb index c4487b2..515e0f6 100644 --- a/spec/manifique/web_client_spec.rb +++ b/spec/manifique/web_client_spec.rb @@ -2,18 +2,18 @@ require "spec_helper" require "manifique/web_client" RSpec.describe Manifique::WebClient do - before do - stub_request(:get, "http://example.com/200_empty"). - to_return(body: "", status: 200, headers: {}) - - stub_request(:get, "http://example.com/404"). - to_return(body: "", status: 404, headers: {}) - - stub_request(:get, "http://example.com/500"). - to_return(body: "", status: 500, headers: {}) - end - describe "#do_get_request" do + before do + stub_request(:get, "http://example.com/404"). + to_return(body: "", status: 404, headers: {}) + + stub_request(:get, "http://example.com/500"). + to_return(body: "", status: 500, headers: {}) + + stub_request(:get, "http://example.com/200_empty"). + to_return(body: "", status: 200, headers: {}) + end + context "unsuccessful requests" do describe "404" do let(:client) { Manifique::WebClient.new } @@ -48,4 +48,30 @@ RSpec.describe Manifique::WebClient do end end end + + describe "#fetch_web_manifest" do + context "link[rel=manifest] present" do + before do + index_html = File.read(File.join(__dir__, "..", "fixtures", "mastodon.html")); + stub_request(:get, "https://kosmos.social/"). + to_return(body: index_html, status: 200, headers: { + "Content-Type": "text/html; charset=utf-8" + }) + manifest = File.read(File.join(__dir__, "..", "fixtures", "mastodon-web-app-manifest.json")); + stub_request(:get, "https://kosmos.social/mastodon-web-app-manifest.json"). + to_return(body: manifest, status: 200, headers: { + "Content-Type": "application/json; charset=utf-8" + }) + end + + let(:agent) { Manifique::WebClient.new(url: "https://kosmos.social") } + + subject { agent.fetch_web_manifest } + + it "fetches and returns the manifest" do + expect(subject).to be_kind_of(Hash) + expect(subject["name"]).to eq("kosmos.social") + end + end + end end