├── phpunit ├── tests ├── bootstrap.php ├── data │ ├── 404.response.txt │ ├── pingback-endpoint.example │ │ ├── 404-response │ │ ├── invalid-xmlrpc │ │ ├── empty-body │ │ ├── invalid-body │ │ ├── valid-response │ │ └── invalid-request │ ├── webmention-endpoint.example │ │ ├── 404-response │ │ ├── 500-response │ │ ├── queued-response │ │ ├── invalid-request │ │ └── created-response │ ├── pingback-target.example │ │ ├── no-endpoint.html │ │ ├── has-valid-endpoint.html │ │ └── has-erroring-endpoint.html │ ├── webmention-target.example │ │ ├── no-endpoint.html │ │ ├── has-valid-endpoint.html │ │ └── has-erroring-endpoint.html │ ├── target.example.com │ │ ├── redirect.html │ │ ├── relative │ │ │ ├── after-redirect.html │ │ │ └── path-relative-endpoint.html │ │ ├── empty-string.html │ │ ├── header.html │ │ ├── only-pingback.html │ │ ├── webmention-created.html │ │ ├── body-a.html │ │ ├── pingback-failed.html │ │ ├── document-order-2.html │ │ ├── webmention-only-failed.html │ │ ├── document-order-1.html │ │ ├── body-link.html │ │ ├── body-link-org.html │ │ ├── body-link-org2.html │ │ ├── false-endpoint-in-comment.html │ │ ├── webmention-failed.html │ │ ├── webmention-rocks-test-2.html │ │ ├── webmention-rocks-test-6.html │ │ ├── webmention-rocks-test-1.html │ │ ├── webmention-rocks-test-4.html │ │ ├── webmention-rocks-test-5.html │ │ ├── webmention-rocks-test-3.html │ │ ├── webmention-rocks-test-7.html │ │ └── webmention-rocks-test-8.html │ └── source.example.com │ │ ├── no-links.html │ │ ├── target-has-both.html │ │ ├── mixed-success-links.html │ │ ├── two-valid-links.html │ │ └── send-to-h-entry-links.html ├── SendWebmentionTest.php ├── SendPingbackTest.php ├── SendMentionsTest.php ├── FindOutgoingLinksTest.php ├── LinkHeaderParserTest.php ├── TagParserTest.php └── DiscoverTest.php ├── .gitignore ├── .travis.yml ├── coverage ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── css │ ├── style.css │ └── nv.d3.min.css ├── js │ ├── html5shiv.min.js │ ├── respond.min.js │ ├── holder.min.js │ └── bootstrap.min.js ├── index.html ├── dashboard.html └── clover.xml ├── CONTRIBUTING.md ├── example.php ├── phpunit.xml ├── composer.json ├── src └── IndieWeb │ ├── MentionClientTest.php │ └── MentionClient.php └── README.md /phpunit: -------------------------------------------------------------------------------- 1 | ./vendor/phpunit/phpunit/phpunit -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | Hello World
8 | -------------------------------------------------------------------------------- /tests/data/webmention-target.example/no-endpoint.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: nginx/1.0.14 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 |Hello World
8 | -------------------------------------------------------------------------------- /tests/data/target.example.com/redirect.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 302 Found 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | Location: relative/after-redirect.html 7 | 8 | Redirecting... 9 | -------------------------------------------------------------------------------- /tests/data/webmention-endpoint.example/created-response: -------------------------------------------------------------------------------- 1 | HTTP/1.1 201 Created 2 | Date: Wed, 09 Dec 2015 04:40:18 GMT 3 | Server: Apache 4 | Connection: close 5 | Vary: Accept-Encoding 6 | Location: http://webmention-endpoint.example/status/skldjfosuet 7 | 8 | Webmention processing queued 9 | -------------------------------------------------------------------------------- /tests/data/pingback-target.example/has-valid-endpoint.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: nginx/1.0.14 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | X-Pingback: http://pingback-endpoint.example/valid-response 7 | 8 |Hello World
9 | -------------------------------------------------------------------------------- /tests/data/pingback-target.example/has-erroring-endpoint.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: nginx/1.0.14 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | X-Pingback: http://pingback-endpoint.example/invalid-request 7 | 8 |Hello World
9 | -------------------------------------------------------------------------------- /tests/data/webmention-target.example/has-valid-endpoint.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: nginx/1.0.14 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | Link:Hello World
9 | -------------------------------------------------------------------------------- /tests/data/target.example.com/relative/after-redirect.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: nginx/1.9.10 3 | Content-Type: text/html; charset=UTF-8 4 | Link:There are no links in this page
13 | 14 | 15 | -------------------------------------------------------------------------------- /example.php: -------------------------------------------------------------------------------- 1 | enableDebug(); 9 | $sent = $client->sendMentions($url); 10 | 11 | echo "Sent $sent mentions\n"; 12 | -------------------------------------------------------------------------------- /tests/data/target.example.com/empty-string.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 |You can send me a webmention
13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/data/source.example.com/target-has-both.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 |You can send a webmention or a pingback here
10 | -------------------------------------------------------------------------------- /tests/data/webmention-target.example/has-erroring-endpoint.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: nginx/1.0.14 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 |Hello World
13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/data/target.example.com/only-pingback.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 |You can send me a pingback
13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/data/target.example.com/webmention-created.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 |You can send me a webmention
13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/data/target.example.com/body-a.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 |You can send me a webmention
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/data/pingback-endpoint.example/empty-body: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Date: Wed, 09 Dec 2015 04:40:18 GMT 3 | Server: Apache 4 | Connection: close 5 | Vary: Accept-Encoding 6 | Content-Type: text/xml; charset=UTF-8 7 | 8 | 9 |You can send me a pingback but it will fail
13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/data/target.example.com/document-order-2.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 |You can send me a webmention or pingback
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/data/target.example.com/webmention-only-failed.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 |You can send me a webmention but it will fail
13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/data/pingback-endpoint.example/valid-response: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Date: Wed, 09 Dec 2015 04:40:18 GMT 3 | Server: Apache 4 | Connection: close 5 | Vary: Accept-Encoding 6 | Content-Type: text/xml; charset=UTF-8 7 | 8 | 9 |You can send me a webmention or pingback
13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/data/target.example.com/body-link.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |You can send me a webmention or pingback
14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/data/target.example.com/body-link-org.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |You can send me a webmention
14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/data/target.example.com/body-link-org2.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |You can send me a webmention
14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/data/source.example.com/mixed-success-links.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 |You can send me a webmention
13 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/data/target.example.com/webmention-failed.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |You can send me a webmention or pingback but the webmention will fail
14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/data/source.example.com/send-to-h-entry-links.html: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Server: Apache 3 | Date: Wed, 09 Dec 2015 03:29:14 GMT 4 | Content-Type: text/html; charset=utf-8 5 | Connection: keep-alive 6 | 7 | 8 | 9 |14 | two 15 |
16 |Link header. The Webmention endpoint is listed as an absolute URL.<a> tag in the body. The Webmention endpoint is listed as an absolute URL.Link header. The URL is relative, so this will also test whether your discovery code properly resolves the relative URL.<link> tag in the document. The Webmention endpoint is listed as an absolute URL.<a> tag in the body. The URL is relative, so this will also test whether your discovery code properly resolves the relative URL.<link> tag in the document. The URL is relative, so this will also test whether your discovery code properly resolves the relative URL.LinK". This helps you test whether you are handling HTTP header names in a case insensitive way.Link header. Unlike tests #1 and #2, the rel value is quoted, since HTTP allows both rel="webmention" and rel=webmention for the Link header.No links here
'); 12 | $this->assertEquals(0, $total); 13 | } 14 | 15 | public function testFromURLWithNoLinks() { 16 | $total = $this->client->sendMentions('http://source.example.com/no-links.html'); 17 | $this->assertEquals(0, $total); 18 | } 19 | 20 | public function testFromURLWithTwoValidLinks() { 21 | $total = $this->client->sendMentions('http://source.example.com/two-valid-links.html'); 22 | $this->assertEquals(2, $total); 23 | } 24 | 25 | public function testFromURLWithOneValidAndOneInvalidLink() { 26 | $total = $this->client->sendMentions('http://source.example.com/mixed-success-links.html'); 27 | $this->assertEquals(1, $total); 28 | } 29 | 30 | public function testDoesNotSendToLinksOutsideHEntry() { 31 | $total = $this->client->sendMentions('http://source.example.com/send-to-h-entry-links.html'); 32 | $this->assertEquals(1, $total); 33 | } 34 | 35 | public function testPrioritizesWebmentionEndpointOverPingback() { 36 | $result = $this->client->sendFirstSupportedMention('http://source.example.com/example.html', 'http://target.example.com/header.html'); 37 | $this->assertEquals('webmention', $result); 38 | } 39 | 40 | public function testFindsPingbackEndpointBecauseNoWebmentionEndpoint() { 41 | $result = $this->client->sendFirstSupportedMention('http://source.example.com/example.html', 'http://target.example.com/only-pingback.html'); 42 | $this->assertEquals('pingback', $result); 43 | } 44 | 45 | public function testDoesNotSendPingbackDespiteWebmentionFail() { 46 | $result = $this->client->sendFirstSupportedMention('http://source.example.com/example.html', 'http://target.example.com/webmention-failed.html'); 47 | $this->assertEquals(false, $result); 48 | } 49 | 50 | public function testSendsFailingPingback() { 51 | $result = $this->client->sendFirstSupportedMention('http://source.example.com/example.html', 'http://target.example.com/pingback-failed.html'); 52 | $this->assertEquals(false, $result); 53 | } 54 | 55 | public function testSendsFailingWebmention() { 56 | $result = $this->client->sendFirstSupportedMention('http://source.example.com/example.html', 'http://target.example.com/webmention-only-failed.html'); 57 | $this->assertEquals(false, $result); 58 | } 59 | 60 | public function testSendsWebmentionAndWasCreated() { 61 | $result = $this->client->sendFirstSupportedMention('http://source.example.com/example.html', 'http://target.example.com/webmention-created.html'); 62 | $this->assertEquals('webmention', $result); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/IndieWeb/MentionClientTest.php: -------------------------------------------------------------------------------- 1 | setAccessible(true); 15 | return $method->invokeArgs($this, $args); 16 | } 17 | 18 | public static function __callStatic($method, $args) { 19 | $method = new \ReflectionMethod('IndieWeb\MentionClient', $method); 20 | $method->setAccessible(true); 21 | return $method->invokeArgs(null, $args); 22 | } 23 | 24 | protected static function _head($url, $headers=array()) { 25 | self::$_redirects_remaining = 5; 26 | $response = self::_read_file($url); 27 | return array( 28 | 'code' => $response['code'], 29 | 'headers' => $response['headers'], 30 | 'url' => $response['url'] 31 | ); 32 | } 33 | 34 | protected static function _get($url, $headers=array()) { 35 | self::$_redirects_remaining = 5; 36 | return self::_read_file($url); 37 | } 38 | 39 | protected static function _post($url, $body, $headers=array()) { 40 | return self::_read_file($url); 41 | } 42 | 43 | private static function _read_file($url) { 44 | if(self::$dataDir) { 45 | $dataDir = self::$dataDir; 46 | } else { 47 | $dataDir = dirname(__FILE__).'/../../tests/data/'; 48 | } 49 | 50 | $filename = $dataDir.preg_replace('/https?:\/\//', '', $url); 51 | if(!file_exists($filename)) { 52 | $filename = dirname(__FILE__).'/../../tests/data/404.response.txt'; 53 | } 54 | $response = file_get_contents($filename); 55 | 56 | $split = explode("\r\n\r\n", $response); 57 | if(count($split) != 2) { 58 | throw new \Exception("Invalid file contents, check that newlines are CRLF: $url"); 59 | } 60 | list($headers, $body) = $split; 61 | 62 | if(preg_match('/HTTP\/1\.1 (\d+)/', $headers, $match)) { 63 | $code = $match[1]; 64 | } 65 | 66 | $headers = preg_replace('/HTTP\/1\.1 \d+ .+/', '', $headers); 67 | $parsedHeaders = self::_parse_headers($headers); 68 | 69 | if(($code == 302 || $code == 301) && array_key_exists('Location', $parsedHeaders)) { 70 | $effectiveUrl = \mf2\resolveUrl($url, $parsedHeaders['Location']); 71 | if(self::$_redirects_remaining > 0) { 72 | self::$_redirects_remaining--; 73 | return self::_read_file($effectiveUrl); 74 | } else { 75 | return [ 76 | 'code' => 0, 77 | 'headers' => $parsedHeaders, 78 | 'body' => $body, 79 | 'error' => 'too_many_redirects', 80 | 'error_description' => '', 81 | 'url' => $effectiveUrl 82 | ]; 83 | } 84 | } else { 85 | $effectiveUrl = $url; 86 | } 87 | 88 | return array( 89 | 'code' => $code, 90 | 'headers' => $parsedHeaders, 91 | 'body' => $body, 92 | 'url' => $effectiveUrl 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tests/FindOutgoingLinksTest.php: -------------------------------------------------------------------------------- 1 | example'; 6 | $links = IndieWeb\MentionClientTest::findOutgoingLinks($html); 7 | $this->assertEquals(array('http://example.com/'), $links); 8 | } 9 | 10 | public function testFindLinkInHEntryContent() { 11 | $html = ''; 12 | $mf2 = Mf2\parse($html, 'http://source.example.net/'); 13 | $links = IndieWeb\MentionClientTest::findOutgoingLinks($mf2); 14 | $this->assertEquals(array('http://example.com/'), $links); 15 | 16 | $html = ''; 17 | $mf2 = Mf2\parse($html, 'http://source.example.net/'); 18 | $links = IndieWeb\MentionClientTest::findOutgoingLinks($mf2); 19 | $this->assertEquals(array('http://example.com/'), $links); 20 | } 21 | 22 | public function testFindLinkInHEntryProperty() { 23 | $html = ''; 24 | $mf2 = Mf2\parse($html, 'http://source.example.net/'); 25 | $links = IndieWeb\MentionClientTest::findOutgoingLinks($mf2); 26 | $this->assertEquals(array('http://example.com/'), $links); 27 | } 28 | 29 | public function testFindLinkInNestedHEntryProperty() { 30 | $html = 'Hello World
| 33 | | Code Coverage |
34 | ||||||||
| 37 | | Lines |
38 | Functions and Methods |
39 | Classes and Traits |
40 | ||||||
| Total | 45 |
46 |
49 |
50 | |
51 | 100.00% |
52 | 229 / 229 |
53 |
54 |
57 |
58 | |
59 | 100.00% |
60 | 18 / 18 |
61 |
62 |
65 |
66 | |
67 | 100.00% |
68 | 1 / 1 |
69 |
| MentionClient.php | 73 |
74 |
77 |
78 | |
79 | 100.00% |
80 | 229 / 229 |
81 |
82 |
85 |
86 | |
87 | 100.00% |
88 | 18 / 18 |
89 |
90 |
93 |
94 | |
95 | 100.00% |
96 | 1 / 1 |
97 |
| Class | 57 |Coverage | 58 |
|---|
| Class | 73 |CRAP | 74 |
|---|
| Method | 110 |Coverage | 111 |
|---|
| Method | 126 |CRAP | 127 |
|---|