diff --git a/controllers/Parse.php b/controllers/Parse.php index 1918eb5..6e7698e 100644 --- a/controllers/Parse.php +++ b/controllers/Parse.php @@ -128,6 +128,8 @@ class Parse { $data['original'] = $parsed['original']; if(isset($parsed['source-format'])) $data['source-format'] = $parsed['source-format']; + if(isset($parsed['url']) && $parsed['url'] != $result['url']) + $data['parsed-url'] = $parsed['url']; return $this->respond($response, 200, $data); } diff --git a/lib/XRay.php b/lib/XRay.php index 5b9f972..7df225c 100644 --- a/lib/XRay.php +++ b/lib/XRay.php @@ -38,9 +38,9 @@ class XRay { $result = $parser->parse($body, $url, $opts); if(!isset($opts['include_original']) || !$opts['include_original']) unset($result['original']); - $result['url'] = $url; - $result['code'] = isset($result['code']) ? $result['code'] : $code; - $result['source-format'] = isset($result['source-format']) ? $result['source-format'] : null; + if(!isset($result['url'])) $result['url'] = $url; + if(!isset($result['code'])) $result['code'] = $code; + if(!isset($result['source-format'])) $result['source-format'] = null; return $result; } @@ -49,10 +49,9 @@ class XRay { $result = $parser->parse($mf2json, $url, $opts); if(!isset($opts['include_original']) || !$opts['include_original']) unset($result['original']); - $result['url'] = $url; - $result['source-format'] = isset($result['source-format']) ? $result['source-format'] : null; + if(!isset($result['url'])) $result['url'] = $url; + if(!isset($result['source-format'])) $result['source-format'] = null; return $result; } } - diff --git a/lib/XRay/Fetcher.php b/lib/XRay/Fetcher.php index a272b01..b1c3223 100644 --- a/lib/XRay/Fetcher.php +++ b/lib/XRay/Fetcher.php @@ -99,7 +99,7 @@ class Fetcher { return [ 'error' => 'invalid_content', 'error_description' => 'The server did not return a recognized content type', - 'content_type' => $result['headers']['Content-Type'], + 'content_type' => $result['headers']['Content-Type'] ?? null, 'url' => $result['url'], 'code' => $result['code'] ]; diff --git a/lib/XRay/Formats/HTML.php b/lib/XRay/Formats/HTML.php index f2a7554..d9b561b 100644 --- a/lib/XRay/Formats/HTML.php +++ b/lib/XRay/Formats/HTML.php @@ -91,9 +91,33 @@ class HTML extends Format { } } - // Now start pulling in the data from the page. Start by looking for microformats2 $mf2 = \mf2\Parse($html, $url); + // Check for a rel=alternate link to a Microformats JSON representation, and use that instead + if(isset($mf2['rel-urls'])) { + foreach($mf2['rel-urls'] as $relurl => $reltype) { + if(in_array('alternate', $reltype['rels']) && $reltype['type'] == 'application/mf2+json') { + // Fetch and parse the MF2 JSON link instead + $jsonpage = $http->get($relurl, [ + 'Accept' => 'application/mf2+json,application/json' + ]); + // Skip and fall back to parsing the HTML if anything about this request fails + if(!$jsonpage['error'] && $jsonpage['body']) { + $jsondata = json_decode($jsonpage['body'],true); + if($jsondata) { + $data = Formats\Mf2::parse($jsondata, $url, $http, $opts); + if($data && is_array($data) && isset($data['data']['type'])) { + $data['url'] = $relurl; + $data['source-format'] = 'mf2+json'; + return $data; + } + } + } + } + } + } + + // Now start pulling in the data from the page. Start by looking for microformats2 if($mf2 && count($mf2['items']) > 0) { $data = Formats\Mf2::parse($mf2, $url, $http, $opts); if($data) { diff --git a/lib/XRay/Formats/Mf2.php b/lib/XRay/Formats/Mf2.php index 357ea56..a2d331f 100644 --- a/lib/XRay/Formats/Mf2.php +++ b/lib/XRay/Formats/Mf2.php @@ -16,7 +16,7 @@ class Mf2 extends Format { } public static function parse($mf2, $url, $http, $opts=[]) { - if(count($mf2['items']) == 0) + if(!isset($mf2['items']) || count($mf2['items']) == 0) return false; // If they are expecting a feed, always return a feed or an error diff --git a/lib/XRay/Parser.php b/lib/XRay/Parser.php index dda17f8..0efb163 100644 --- a/lib/XRay/Parser.php +++ b/lib/XRay/Parser.php @@ -54,12 +54,13 @@ class Parser { } if(substr($body, 0, 1) == '{') { - $feeddata = json_decode($body, true); - if($feeddata && isset($feeddata['version']) && $feeddata['version'] == 'https://jsonfeed.org/version/1') { - return Formats\JSONFeed::parse($feeddata, $url); - } elseif($feeddata && isset($feeddata['items'][0]['type']) && isset($feeddata['items'][0]['properties'])) { - // Check if an mf2 JSON object was passed in - $data = Formats\Mf2::parse($feeddata, $url, $this->http, $opts); + $parsed = json_decode($body, true); + if($parsed && isset($parsed['version']) && $parsed['version'] == 'https://jsonfeed.org/version/1') { + return Formats\JSONFeed::parse($parsed, $url); + // TODO: check for an activitystreams object too + } elseif($parsed && isset($parsed['items'][0]['type']) && isset($parsed['items'][0]['properties'])) { + // Check if an mf2 JSON string was passed in + $data = Formats\Mf2::parse($parsed, $url, $this->http, $opts); $data['source-format'] = 'mf2+json'; return $data; } @@ -67,7 +68,8 @@ class Parser { // No special parsers matched, parse for Microformats now $data = Formats\HTML::parse($this->http, $body, $url, $opts); - $data['source-format'] = 'mf2+html'; + if(!isset($data['source-format'])) + $data['source-format'] = 'mf2+html'; return $data; } diff --git a/tests/ParseTest.php b/tests/ParseTest.php index 6507f97..b71c7e8 100644 --- a/tests/ParseTest.php +++ b/tests/ParseTest.php @@ -876,4 +876,56 @@ class ParseTest extends PHPUnit_Framework_TestCase { $this->assertEquals('The content of the blog post', $data['data']['content']['text']); } + public function testRelAlternateToMf2JSON() { + $url = 'http://source.example.com/rel-alternate-mf2-json'; + $response = $this->parse(['url' => $url]); + + $body = $response->getContent(); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode($body, true); + + $this->assertEquals('mf2+json', $data['source-format']); + $this->assertEquals('http://source.example.com/rel-alternate-mf2-json.json', $data['parsed-url']); + $this->assertEquals('Pretty great to see a new self-hosted IndieAuth server! Congrats @nilshauk, and great project name! https://twitter.com/nilshauk/status/1017485223716630528', $data['data']['content']['text']); + } + + public function testRelAlternateToNotFoundURL() { + $url = 'http://source.example.com/rel-alternate-not-found'; + $response = $this->parse(['url' => $url]); + + $body = $response->getContent(); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode($body, true); + + $this->assertEquals('mf2+html', $data['source-format']); + $this->assertArrayNotHasKey('parsed-url', $data); + $this->assertEquals('Test content with a rel alternate link to a 404 page', $data['data']['content']['text']); + } + + public function testRelAlternatePrioritizesJSON() { + $url = 'http://source.example.com/rel-alternate-priority'; + $response = $this->parse(['url' => $url]); + + $body = $response->getContent(); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode($body, true); + + $this->assertEquals('mf2+json', $data['source-format']); + $this->assertEquals('http://source.example.com/rel-alternate-priority.json', $data['parsed-url']); + $this->assertEquals('This should be the content from XRay', $data['data']['content']['text']); + } + + public function testRelAlternateFallsBackOnInvalidJSON() { + $url = 'http://source.example.com/rel-alternate-fallback'; + $response = $this->parse(['url' => $url]); + + $body = $response->getContent(); + $this->assertEquals(200, $response->getStatusCode()); + $data = json_decode($body, true); + + $this->assertEquals('mf2+html', $data['source-format']); + $this->assertArrayNotHasKey('parsed-url', $data); + $this->assertEquals('XRay should use this content since the JSON in the rel-alternate is invalid', $data['data']['content']['text']); + } + } diff --git a/tests/data/source.example.com/rel-alternate-fallback b/tests/data/source.example.com/rel-alternate-fallback new file mode 100644 index 0000000..5644374 --- /dev/null +++ b/tests/data/source.example.com/rel-alternate-fallback @@ -0,0 +1,19 @@ +HTTP/1.1 200 OK +Server: Apache +Date: Wed, 09 Dec 2015 03:29:14 GMT +Content-Type: text/html +Connection: keep-alive + + + + + + Test + + + +
+

XRay should use this content since the JSON in the rel-alternate is invalid

+
+ + diff --git a/tests/data/source.example.com/rel-alternate-fallback.json b/tests/data/source.example.com/rel-alternate-fallback.json new file mode 100644 index 0000000..d9c1be7 --- /dev/null +++ b/tests/data/source.example.com/rel-alternate-fallback.json @@ -0,0 +1,16 @@ +HTTP/1.1 200 OK +Server: Apache +Date: Wed, 09 Dec 2015 03:29:14 GMT +Content-Type: application/mf2+json +Connection: keep-alive + +{ + "type": [ + "h-entry" + ], + "properties": { + "content": [ + "XRay should not use this content since the JSON must be an entire page parsed result" + ] + } +} diff --git a/tests/data/source.example.com/rel-alternate-mf2-json b/tests/data/source.example.com/rel-alternate-mf2-json new file mode 100644 index 0000000..48085f6 --- /dev/null +++ b/tests/data/source.example.com/rel-alternate-mf2-json @@ -0,0 +1,580 @@ +HTTP/1.1 200 OK +Server: Apache +Date: Wed, 09 Dec 2015 03:29:14 GMT +Content-Type: text/html +Connection: keep-alive + + + + + + + Pretty great to see a new self-hosted IndieAuth server! ... • Aaron Parecki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/source.example.com/rel-alternate-mf2-json.json b/tests/data/source.example.com/rel-alternate-mf2-json.json new file mode 100644 index 0000000..2e4fd65 --- /dev/null +++ b/tests/data/source.example.com/rel-alternate-mf2-json.json @@ -0,0 +1,692 @@ +HTTP/1.1 200 OK +Server: Apache +Date: Wed, 09 Dec 2015 03:29:14 GMT +Content-Type: application/mf2+json +Connection: keep-alive + +{ + "items": [ + { + "type": [ + "h-entry" + ], + "properties": { + "name": [ + "Pretty great to see a new self-hosted IndieAuth server! Congrats @nilshauk, and great project name! https://twitter.com/nilshauk/status/1017485223716630528" + ], + "category": [ + "indieauth" + ], + "url": [ + "https://aaronparecki.com/2018/07/12/10/indieauth" + ], + "syndication": [ + "https://twitter.com/aaronpk/status/1017500609631567872" + ], + "author": [ + "https://aaronparecki.com/" + ], + "published": [ + "2018-07-12T13:02:04-07:00" + ], + "content": [ + { + "html": "Pretty great to see a new self-hosted IndieAuth server! Congrats @nilshauk, and great project name! https://twitter.com/nilshauk/status/1017485223716630528", + "value": "Pretty great to see a new self-hosted IndieAuth server! Congrats @nilshauk, and great project name! https://twitter.com/nilshauk/status/1017485223716630528" + } + ], + "location": [ + { + "type": [ + "h-adr" + ], + "properties": { + "locality": [ + "Portland" + ], + "region": [ + "Oregon" + ], + "country": [ + "USA" + ], + "latitude": [ + "45.5354" + ], + "longitude": [ + "-122.62099" + ] + }, + "value": "Portland, Oregon, USA \u2022 84\u00b0F" + } + ], + "like": [ + { + "type": [ + "h-cite" + ], + "properties": { + "url": [ + "https://twitter.com/aaronpk/status/1017500609631567872#favorited-by-75276568" + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Nils Norman Hauk\u00e5s" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/40aa1ddaef3cf2abc9392d731dd6f150b2ec097243351c2c1a46f061c4127e2c.jpg" + ], + "url": [ + "https://twitter.com/nilshauk" + ] + }, + "value": "Nils Norman Hauk\u00e5s" + } + ] + }, + "value": "https://pkcdn.xyz/pbs.twimg.com/40aa1ddaef3cf2abc9392d731dd6f150b2ec097243351c2c1a46f061c4127e2c.jpg Nils Norman Hauk\u00e5s" + }, + { + "type": [ + "h-cite" + ], + "properties": { + "url": [ + "https://twitter.com/aaronpk/status/1017500609631567872#favorited-by-798123" + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Knut Melv\u00e6r" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/fc0678c0424632fb0ce6a0d5bdd2697bf8edbb9086e819f2453aadf1eeb58d5a.jpg" + ], + "url": [ + "https://twitter.com/kmelve" + ] + }, + "value": "Knut Melv\u00e6r" + } + ] + }, + "value": "https://pkcdn.xyz/pbs.twimg.com/fc0678c0424632fb0ce6a0d5bdd2697bf8edbb9086e819f2453aadf1eeb58d5a.jpg Knut Melv\u00e6r" + }, + { + "type": [ + "h-cite" + ], + "properties": { + "url": [ + "https://twitter.com/aaronpk/status/1017500609631567872#favorited-by-1202561" + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Michael Sullivan" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/2a0f14011833a9deca627931442e780a6e00fb3221e7c98a4b1045794d05f8dc.jpg" + ], + "url": [ + "https://twitter.com/sull" + ] + }, + "value": "Michael Sullivan" + } + ] + }, + "value": "https://pkcdn.xyz/pbs.twimg.com/2a0f14011833a9deca627931442e780a6e00fb3221e7c98a4b1045794d05f8dc.jpg Michael Sullivan" + }, + { + "type": [ + "h-cite" + ], + "properties": { + "url": [ + "https://twitter.com/aaronpk/status/1017500609631567872#favorited-by-16114199" + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "cathieleblanc" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/36de4c45d8c4c4b420607c8e490e8777ec5b658dfc57b1d9f90b54636dc8c3e7.jpg" + ], + "url": [ + "https://twitter.com/cathieleblanc" + ] + }, + "value": "cathieleblanc" + } + ] + }, + "value": "https://pkcdn.xyz/pbs.twimg.com/36de4c45d8c4c4b420607c8e490e8777ec5b658dfc57b1d9f90b54636dc8c3e7.jpg cathieleblanc" + }, + { + "type": [ + "h-cite" + ], + "properties": { + "url": [ + "https://twitter.com/aaronpk/status/1017500609631567872#favorited-by-961661" + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "TomWithTheWeather" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/ce4f2f04b015ad5bd826584ceac5e6dbf0c8c1b9be2bdce80df7bc7a1d83bdcd.jpeg" + ], + "url": [ + "https://twitter.com/tomwiththeweath" + ] + }, + "value": "TomWithTheWeather" + } + ] + }, + "value": "https://pkcdn.xyz/pbs.twimg.com/ce4f2f04b015ad5bd826584ceac5e6dbf0c8c1b9be2bdce80df7bc7a1d83bdcd.jpeg TomWithTheWeather" + }, + { + "type": [ + "h-cite" + ], + "properties": { + "url": [ + "https://twitter.com/aaronpk/status/1017500609631567872#favorited-by-18331731" + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Pelle Wessman" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/500a4883279015b8c0bf56f607034761ddc0c366c0275632662441f25af5351c.png" + ], + "url": [ + "https://twitter.com/voxpelli" + ] + }, + "value": "Pelle Wessman" + } + ] + }, + "value": "https://pkcdn.xyz/pbs.twimg.com/500a4883279015b8c0bf56f607034761ddc0c366c0275632662441f25af5351c.png Pelle Wessman" + } + ], + "comment": [ + { + "type": [ + "h-cite" + ], + "properties": { + "name": [ + "Thank you very much. :)" + ], + "url": [ + "https://twitter.com/nilshauk/status/1017501170376560640" + ], + "published": [ + "2018-07-12T20:09:17+00:00" + ], + "content": [ + { + "html": "Thank you very much. :)", + "value": "Thank you very much. :)" + } + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Nils Norman Hauk\u00e5s" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/40aa1ddaef3cf2abc9392d731dd6f150b2ec097243351c2c1a46f061c4127e2c.jpg" + ], + "url": [ + "http://nilsnh.no" + ] + }, + "value": "Nils Norman Hauk\u00e5s" + } + ] + }, + "value": "Thank you very much. :)" + }, + { + "type": [ + "h-cite" + ], + "properties": { + "name": [ + "Looking forward to learning more about IndieWeb and hopefully contribute some more. :) I'm like, \"surely we can build cooler and more usable services than present silo offerings.\"" + ], + "url": [ + "https://twitter.com/nilshauk/status/1017512103199068160" + ], + "published": [ + "2018-07-12T20:52:44+00:00" + ], + "content": [ + { + "html": "Looking forward to learning more about IndieWeb and hopefully contribute some more. :) I'm like, \"surely we can build cooler and more usable services than present silo offerings.\"", + "value": "Looking forward to learning more about IndieWeb and hopefully contribute some more. :) I'm like, \"surely we can build cooler and more usable services than present silo offerings.\"" + } + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Nils Norman Hauk\u00e5s" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/40aa1ddaef3cf2abc9392d731dd6f150b2ec097243351c2c1a46f061c4127e2c.jpg" + ], + "url": [ + "http://nilsnh.no" + ] + }, + "value": "Nils Norman Hauk\u00e5s" + } + ] + }, + "value": "Looking forward to learning more about IndieWeb and hopefully contribute some more. :) I'm like, \"surely we can build cooler and more usable services than present silo offerings.\"" + }, + { + "type": [ + "h-cite" + ], + "properties": { + "name": [ + "I was just talking about the words \u201ccellar door\u201d the other day. Cool project.\n\nen.m.wikipedia.org/wiki/Cellar_do\u2026" + ], + "url": [ + "https://twitter.com/sull/status/1017546958590922758" + ], + "published": [ + "2018-07-12T23:11:14+00:00" + ], + "content": [ + { + "html": "I was just talking about the words “cellar door” the other day. Cool project.

en.m.wikipedia.org/wiki/Cellar_do…", + "value": "I was just talking about the words \u201ccellar door\u201d the other day. Cool project.\n\nen.m.wikipedia.org/wiki/Cellar_do\u2026" + } + ], + "author": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Michael Sullivan" + ], + "photo": [ + "https://pkcdn.xyz/pbs.twimg.com/2a0f14011833a9deca627931442e780a6e00fb3221e7c98a4b1045794d05f8dc.jpg" + ], + "url": [ + "https://keybase.io/sull" + ] + }, + "value": "Michael Sullivan" + } + ] + }, + "value": "I was just talking about the words \u201ccellar door\u201d the other day. Cool project.\n\nen.m.wikipedia.org/wiki/Cellar_do\u2026" + } + ] + } + }, + { + "type": [ + "h-card" + ], + "properties": { + "note": [ + "Hi, I'm Aaron Parecki, co-founder of IndieWebCamp. I maintain oauth.net, write and consult about OAuth, and am the editor of several W3C specfications. I record videos for local conferences and help run a podcast studio in Portland.\nI wrote 100 songs in 100 days! I've been tracking my location since 2008, and write down everything I eat and drink. I've spoken at conferences around the world about owning your data, OAuth, quantified self, and explained why R is a vowel." + ], + "name": [ + "Aaron Parecki" + ], + "callsign": [ + "W7APK" + ], + "url": [ + "https://aaronparecki.com/", + "https://w7apk.com" + ], + "uid": [ + "https://aaronparecki.com/" + ], + "photo": [ + "https://aaronparecki.com/images/profile.jpg" + ], + "bday": [ + "--12-28" + ], + "org": [ + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "IndieWebCamp" + ], + "url": [ + "https://indieweb.org/" + ] + }, + "value": "IndieWebCamp" + }, + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "oauth.net" + ], + "url": [ + "https://oauth.net/" + ] + }, + "value": "oauth.net" + }, + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Okta" + ], + "role": [ + "Developer Advocate" + ], + "photo": [ + "https://aaronparecki.com/images/okta.png" + ], + "url": [ + "https://developer.okta.com/" + ] + }, + "value": "Okta" + }, + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "IndieWebCamp" + ], + "role": [ + "Founder" + ], + "photo": [ + "https://aaronparecki.com/images/indiewebcamp.png" + ], + "url": [ + "https://indieweb.org/" + ] + }, + "value": "IndieWebCamp" + }, + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "W3C" + ], + "role": [ + "Editor" + ], + "photo": [ + "https://aaronparecki.com/images/w3c.png" + ], + "url": [ + "https://www.w3.org/" + ] + }, + "value": "W3C" + }, + { + "type": [ + "h-card" + ], + "properties": { + "name": [ + "Stream PDX" + ], + "role": [ + "Co-Founder" + ], + "photo": [ + "https://aaronparecki.com/images/streampdx.png" + ], + "url": [ + "https://streampdx.com" + ] + }, + "value": "Stream PDX" + }, + { + "type": [ + "h-card" + ], + "properties": { + "photo": [ + "https://aaronparecki.com/images/backpedal.png" + ], + "url": [ + "https://backpedal.tv" + ], + "name": [ + "backpedal.tv" + ] + }, + "value": "backpedal.tv" + } + ] + } + } + ], + "rels": { + "alternate": [ + "https://aaronparecki.com/2018/07/12/10/indieauth.json", + "https://aaronparecki.com/2018/07/12/10/indieauth.jf2", + "https://aaronparecki.com/2018/07/12/10/indieauth.as2" + ], + "webmention": [ + "https://webmention.io/aaronpk/webmention" + ], + "stylesheet": [ + "https://aaronparecki.com/semantic/2.2.6/semantic.min.css", + "https://aaronparecki.com/assets/icomoon/style.css", + "https://aaronparecki.com/assets/weather-icons/css/weather-icons.css", + "https://aaronparecki.com/assets/featherlight-1.5.0/featherlight.min.css", + "https://aaronparecki.com/assets/jquery-ui-1.11.4.custom/jquery-ui.min.css", + "https://aaronparecki.com/assets/admin.css", + "https://aaronparecki.com/assets/pulse.css", + "https://aaronparecki.com/assets/styles.3.css", + "https://aaronparecki.com/site/styles.1.css", + "https://aaronparecki.com/assets/carbon.css", + "https://aaronparecki.com/assets/story.css" + ], + "openid.delegate": [ + "https://aaronparecki.com/" + ], + "openid.server": [ + "https://openid.indieauth.com/openid" + ], + "nofollow": [ + "https://en.m.wikipedia.org/wiki/Cellar_door" + ], + "pgpkey": [ + "https://aaronparecki.com/key.txt" + ], + "me": [ + "sms:+15035678642", + "https://micro.blog/aaronpk" + ], + "license": [ + "http://creativecommons.org/licenses/by/3.0/" + ] + }, + "rel-urls": { + "https://aaronparecki.com/2018/07/12/10/indieauth.json": { + "type": "application/mf2+json", + "rels": [ + "alternate" + ] + }, + "https://aaronparecki.com/2018/07/12/10/indieauth.jf2": { + "type": "application/jf2+json", + "rels": [ + "alternate" + ] + }, + "https://aaronparecki.com/2018/07/12/10/indieauth.as2": { + "type": "application/activity+json", + "rels": [ + "alternate" + ] + }, + "https://webmention.io/aaronpk/webmention": { + "rels": [ + "webmention" + ] + }, + "https://aaronparecki.com/semantic/2.2.6/semantic.min.css": { + "type": "text/css", + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/icomoon/style.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/weather-icons/css/weather-icons.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/featherlight-1.5.0/featherlight.min.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/jquery-ui-1.11.4.custom/jquery-ui.min.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/admin.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/pulse.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/styles.3.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/site/styles.1.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/carbon.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/assets/story.css": { + "rels": [ + "stylesheet" + ] + }, + "https://aaronparecki.com/": { + "rels": [ + "openid.delegate" + ] + }, + "https://openid.indieauth.com/openid": { + "rels": [ + "openid.server" + ] + }, + "https://en.m.wikipedia.org/wiki/Cellar_door": { + "text": "en.m.wikipedia.org/wiki/Cellar_do\u2026", + "rels": [ + "nofollow" + ] + }, + "https://aaronparecki.com/key.txt": { + "rels": [ + "pgpkey" + ] + }, + "sms:+15035678642": { + "rels": [ + "me" + ] + }, + "https://micro.blog/aaronpk": { + "rels": [ + "me" + ] + }, + "http://creativecommons.org/licenses/by/3.0/": { + "text": "Creative Commons Attribution 3.0 License", + "rels": [ + "license" + ] + } + } +} diff --git a/tests/data/source.example.com/rel-alternate-not-found b/tests/data/source.example.com/rel-alternate-not-found new file mode 100644 index 0000000..36b7739 --- /dev/null +++ b/tests/data/source.example.com/rel-alternate-not-found @@ -0,0 +1,20 @@ +HTTP/1.1 200 OK +Server: Apache +Date: Wed, 09 Dec 2015 03:29:14 GMT +Content-Type: text/html +Connection: keep-alive + + + + + + Test + + + + +
+

Test content with a rel alternate link to a 404 page

+
+ + diff --git a/tests/data/source.example.com/rel-alternate-priority b/tests/data/source.example.com/rel-alternate-priority new file mode 100644 index 0000000..bcc882f --- /dev/null +++ b/tests/data/source.example.com/rel-alternate-priority @@ -0,0 +1,19 @@ +HTTP/1.1 200 OK +Server: Apache +Date: Wed, 09 Dec 2015 03:29:14 GMT +Content-Type: text/html +Connection: keep-alive + + + + + + Test + + + +
+

This should not be the content from XRay

+
+ + diff --git a/tests/data/source.example.com/rel-alternate-priority.json b/tests/data/source.example.com/rel-alternate-priority.json new file mode 100644 index 0000000..a3839ba --- /dev/null +++ b/tests/data/source.example.com/rel-alternate-priority.json @@ -0,0 +1,33 @@ +HTTP/1.1 200 OK +Server: Apache +Date: Wed, 09 Dec 2015 03:29:14 GMT +Content-Type: application/mf2+json +Connection: keep-alive + +{ + "items": [ + { + "type": [ + "h-entry" + ], + "properties": { + "content": [ + "This should be the content from XRay" + ] + } + } + ], + "rels": { + "alternate": [ + "http://source.example.com/rel-alternate-priority.json" + ] + }, + "rel-urls": { + "http://source.example.com/rel-alternate-priority.json": { + "type": "application/mf2+json", + "rels": [ + "alternate" + ] + } + } +}