indieweb-endpoints 0.3.0 → 0.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66554d42a1533c2688aeb99e1e1a2ab802640ef6cfce21794c34ee9eef2d6b7a
4
- data.tar.gz: 171055da85c2b49b5c02657006d87c43691ddd0eae08cd76ece4a7dacd9abe10
3
+ metadata.gz: 9cb1b27367683210b63651d8195e6d12013f994be97d8c216b2e2165429c4adb
4
+ data.tar.gz: 587e29ea23c02d6de575cefbc6a5f9a808c5e6b47bf662ee138ceaadba03c57f
5
5
  SHA512:
6
- metadata.gz: e6d27232e1d39f0c388227e3acbeea0348f932e96849b6b31d1a417139b51aab1ae1a08f3fdf4fba8bf2b8ba2218f5fa93b4465040b9f0b584686bdf85fcaefc
7
- data.tar.gz: 345f9bbc800fa538c0f7c7a03ff7b4f703c71f56d4efe69148c959bc6043f91b80c65be247d5d5f2b1f1ada3724e387d1720444c98c069aae605521d96259939
6
+ metadata.gz: 1ca06c752aa3ff624d1ab3dbcad733d69bd5ab701ccdac754e7f5bc4e4d7c70ee8b42b23dd911448fb85fab44264e2e7f3c9c136cb23f5b4aaad282a21555ec7
7
+ data.tar.gz: adbb98ffc16e4664d8ea47a94bdfb32b5fbd552155716a1928bf3b62fbdd4bc545768d00ce046101db454b8a71752acdb14330c99e57c1597eca73b8b0e71b93
@@ -2,8 +2,12 @@ require:
2
2
  - rubocop-performance
3
3
  - rubocop-rspec
4
4
 
5
+ Layout/AlignHash:
6
+ EnforcedHashRocketStyle: table
7
+
5
8
  Metrics/BlockLength:
6
9
  Exclude:
10
+ - indieweb-endpoints.gemspec
7
11
  - spec/**/*.rb
8
12
 
9
13
  Metrics/LineLength:
@@ -2,7 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 2.4.6
4
4
  - 2.5.5
5
- - 2.6.2
5
+ - 2.6.3
6
6
  cache:
7
7
  - bundler
8
8
  before_install:
@@ -1,8 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 / 2019-05-09
4
+
5
+ - Add support for Microsub endpoint discovery ([5e81d9f](https://github.com/indieweb/indieweb-endpoints-ruby/commit/5e81d9f)).
6
+ - Refactor parsers to ignore URLs with fragments ([797b376](https://github.com/indieweb/indieweb-endpoints-ruby/commit/797b376)).
7
+ - Rescue `NoMethodError` (for `nil`) and `TypeError` (for non-`String`) ([e33522e](https://github.com/indieweb/indieweb-endpoints-ruby/commit/e33522e)).
8
+ - Raise `ArgumentError` if url scheme is not `http` or `https` ([8eb1b1a](https://github.com/indieweb/indieweb-endpoints-ruby/commit/8eb1b1a)).
9
+ - Shorten up User Agent string ([f9717b4](https://github.com/indieweb/indieweb-endpoints-ruby/commit/f9717b4)).
10
+ - Refactor `HTTPRequest` class using specification defaults ([feef2ba](https://github.com/indieweb/indieweb-endpoints-ruby/commit/feef2ba)).
11
+
12
+ ## 0.4.0 / 2019-05-01
13
+
14
+ - Add `IndieWeb::Endpoints.client` method ([c4d42d0](https://github.com/indieweb/indieweb-endpoints-ruby/commit/c4d42d0)).
15
+ - Rename base `Error` class to `IndieWebEndpointsError` ([d6d6f98](https://github.com/indieweb/indieweb-endpoints-ruby/commit/d6d6f98)).
16
+ - Add `HttpRequest` class ([7864cbd](https://github.com/indieweb/indieweb-endpoints-ruby/commit/7864cbd)).
17
+
3
18
  ## 0.3.0 / 2019-04-30
4
19
 
5
- - `IndieWeb::Endpoints::Client#endpoints` returns an `OpenStruct` instead of a `Hash` ([c209b0b](https://github.com/indieweb/indieweb-endpoints-ruby/commit/c209b0b))
20
+ - `IndieWeb::Endpoints::Client#endpoints` returns an `OpenStruct` instead of a `Hash` ([c209b0b](https://github.com/indieweb/indieweb-endpoints-ruby/commit/c209b0b)).
6
21
 
7
22
  ## 0.2.0 / 2019-04-25
8
23
 
@@ -8,7 +8,7 @@ There are a couple ways you can help improve indieweb-endpoints-ruby:
8
8
 
9
9
  ## Getting Started
10
10
 
11
- indieweb-endpoints-ruby is developed using Ruby 2.4.6 and is additionally tested against Ruby 2.5.5 and 2.6.2 using [Travis CI](https://travis-ci.com/indieweb/indieweb-endpoints-ruby).
11
+ indieweb-endpoints-ruby is developed using Ruby 2.4.6 and is additionally tested against Ruby 2.5.5 and 2.6.3 using [Travis CI](https://travis-ci.com/indieweb/indieweb-endpoints-ruby).
12
12
 
13
13
  Before making changes to indieweb-endpoints-ruby, you'll want to install Ruby 2.4.6. It's recommended that you use a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm). Once you've installed Ruby 2.4.6 using your method of choice, install the project's gems by running:
14
14
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # indieweb-endpoints-ruby
2
2
 
3
- **A Ruby gem for discovering a URL's [IndieAuth](https://indieweb.org/IndieAuth), [Micropub](https://indieweb.org/Micropub), and [Webmention](https://indieweb.org/Webmention) endpoints.**
3
+ **A Ruby gem for discovering a URL's [IndieAuth](https://indieweb.org/IndieAuth), [Micropub](https://indieweb.org/Micropub), [Microsub](https://indieweb.org/Microsub), and [Webmention](https://indieweb.org/Webmention) endpoints.**
4
4
 
5
5
  [![Gem](https://img.shields.io/gem/v/indieweb-endpoints.svg?style=for-the-badge)](https://rubygems.org/gems/indieweb-endpoints)
6
6
  [![Downloads](https://img.shields.io/gem/dt/indieweb-endpoints.svg?style=for-the-badge)](https://rubygems.org/gems/indieweb-endpoints)
@@ -18,7 +18,7 @@
18
18
 
19
19
  Before installing and using indieweb-endpoints-ruby, you'll want to have [Ruby](https://www.ruby-lang.org) 2.4 (or newer) installed. It's recommended that you use a Ruby version managment tool like [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [rvm](https://github.com/rvm/rvm).
20
20
 
21
- indieweb-endpoints-ruby is developed using Ruby 2.4.6 and is additionally tested against Ruby 2.5.5 and 2.6.2 using [Travis CI](https://travis-ci.com/indieweb/indieweb-endpoints-ruby).
21
+ indieweb-endpoints-ruby is developed using Ruby 2.4.6 and is additionally tested against Ruby 2.5.5 and 2.6.3 using [Travis CI](https://travis-ci.com/indieweb/indieweb-endpoints-ruby).
22
22
 
23
23
  ## Installation
24
24
 
@@ -56,6 +56,7 @@ This example will search `https://aaronparecki.com` for valid IndieAuth, Micropu
56
56
  {
57
57
  authorization_endpoint: 'https://aaronparecki.com/auth',
58
58
  micropub: 'https://aaronparecki.com/micropub',
59
+ microsub: 'https://aperture.p3k.io/microsub/1',
59
60
  redirect_uri: nil,
60
61
  token_endpoint: 'https://aaronparecki.com/auth/token',
61
62
  webmention: 'https://webmention.io/aaronpk/webmention'
@@ -66,12 +67,12 @@ Each attribute will return either a `String` representing a URL or `nil`. The `r
66
67
 
67
68
  ### Advanced Usage
68
69
 
69
- Should the need arise, you may work directly with the `IndieWeb::Endpoints::Client` class:
70
+ Should the need arise, you may work with the `IndieWeb::Endpoints::Client` class:
70
71
 
71
72
  ```ruby
72
73
  require 'indieweb/endpoints'
73
74
 
74
- client = IndieWeb::Endpoints::Client.new('https://aaronparecki.com')
75
+ client = IndieWeb::Endpoints.client('https://aaronparecki.com')
75
76
 
76
77
  puts client.response # => #<HTTP::Response …>
77
78
  puts client.endpoints # => #<OpenStruct …>
@@ -80,7 +81,7 @@ puts client.endpoints.webmention # => 'https://webmention.io/aaronpk/webmention'
80
81
 
81
82
  ### Exception Handling
82
83
 
83
- There are several exceptions that may be raised by indieweb-endpoints-ruby's underlying dependencies. These errors are raised as subclasses of `IndieWeb::Endpoints::Error` (which itself is a subclass of `StandardError`).
84
+ There are several exceptions that may be raised by indieweb-endpoints-ruby's underlying dependencies. These errors are raised as subclasses of `IndieWebEndpointsError` (which itself is a subclass of `StandardError`).
84
85
 
85
86
  From [jgarber623/absolutely](https://github.com/jgarber623/absolutely) and [sporkmonger/addressable](https://github.com/sporkmonger/addressable):
86
87
 
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.authors = ['Jason Garber']
12
12
  spec.email = ['jason@sixtwothree.org']
13
13
 
14
- spec.summary = 'Discover a URL’s IndieAuth, Micropub, and Webmention endpoints.'
14
+ spec.summary = 'Discover a URL’s IndieAuth, Micropub, Microsub, and Webmention endpoints.'
15
15
  spec.description = spec.summary
16
16
  spec.homepage = 'https://github.com/indieweb/indieweb-endpoints-ruby'
17
17
  spec.license = 'MIT'
@@ -20,17 +20,22 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.require_paths = ['lib']
22
22
 
23
+ spec.metadata = {
24
+ 'bug_tracker_uri' => "#{spec.homepage}/issues",
25
+ 'changelog_uri' => "#{spec.homepage}/blob/v#{spec.version}/CHANGELOG.md"
26
+ }
27
+
23
28
  spec.add_development_dependency 'rake', '~> 12.3'
24
29
  spec.add_development_dependency 'reek', '~> 5.4'
25
30
  spec.add_development_dependency 'rspec', '~> 3.8'
26
- spec.add_development_dependency 'rubocop', '~> 0.67.2'
31
+ spec.add_development_dependency 'rubocop', '~> 0.68.1'
27
32
  spec.add_development_dependency 'rubocop-performance', '~> 1.1'
28
33
  spec.add_development_dependency 'rubocop-rspec', '~> 1.32'
29
34
  spec.add_development_dependency 'simplecov', '~> 0.16.1'
30
35
  spec.add_development_dependency 'simplecov-console', '~> 0.4.2'
31
36
  spec.add_development_dependency 'webmock', '~> 3.5'
32
37
 
33
- spec.add_runtime_dependency 'absolutely', '~> 2.0'
38
+ spec.add_runtime_dependency 'absolutely', '~> 2.1'
34
39
  spec.add_runtime_dependency 'addressable', '~> 2.6'
35
40
  spec.add_runtime_dependency 'http', '~> 5.0.0.pre'
36
41
  spec.add_runtime_dependency 'nokogiri', '~> 1.10'
@@ -7,19 +7,27 @@ require 'indieweb/endpoints/version'
7
7
  require 'indieweb/endpoints/exceptions'
8
8
 
9
9
  require 'indieweb/endpoints/client'
10
+ require 'indieweb/endpoints/http_request'
10
11
  require 'indieweb/endpoints/registerable'
11
12
 
12
13
  require 'indieweb/endpoints/parsers'
13
14
  require 'indieweb/endpoints/parsers/authorization_endpoint_parser'
14
15
  require 'indieweb/endpoints/parsers/micropub_parser'
16
+ require 'indieweb/endpoints/parsers/microsub_parser'
15
17
  require 'indieweb/endpoints/parsers/redirect_uri_parser'
16
18
  require 'indieweb/endpoints/parsers/token_endpoint_parser'
17
19
  require 'indieweb/endpoints/parsers/webmention_parser'
18
20
 
19
21
  module IndieWeb
20
22
  module Endpoints
21
- def self.get(url)
22
- Client.new(url).endpoints
23
+ class << self
24
+ def client(url)
25
+ Client.new(url)
26
+ end
27
+
28
+ def get(url)
29
+ client(url).endpoints
30
+ end
23
31
  end
24
32
  end
25
33
  end
@@ -1,19 +1,14 @@
1
1
  module IndieWeb
2
2
  module Endpoints
3
3
  class Client
4
- HTTP_HEADERS_OPTS = {
5
- accept: '*/*',
6
- user_agent: 'IndieAuth, Micropub, and Webmention Endpoint Discovery (https://rubygems.org/gems/indieweb-endpoints)'
7
- }.freeze
8
-
9
4
  def initialize(url)
10
- raise ArgumentError, "url must be a String (given #{url.class.name})" unless url.is_a?(String)
11
-
12
- @url = Addressable::URI.parse(url)
5
+ @uri = Addressable::URI.parse(url)
13
6
 
14
- raise ArgumentError, 'url must be an absolute URL (e.g. https://example.com)' unless @url.absolute?
7
+ raise ArgumentError, 'url must be an absolute URL (e.g. https://example.com)' unless @uri.absolute? && @uri.scheme.match?(/^https?$/)
15
8
  rescue Addressable::URI::InvalidURIError => exception
16
9
  raise InvalidURIError, exception
10
+ rescue NoMethodError, TypeError
11
+ raise ArgumentError, "url must be a String (given #{url.class})"
17
12
  end
18
13
 
19
14
  def endpoints
@@ -21,11 +16,7 @@ module IndieWeb
21
16
  end
22
17
 
23
18
  def response
24
- @response ||= HTTP.follow.headers(HTTP_HEADERS_OPTS).timeout(connect: 10, read: 10).get(@url)
25
- rescue HTTP::ConnectionError,
26
- HTTP::TimeoutError,
27
- HTTP::Redirector::TooManyRedirectsError => exception
28
- raise IndieWeb::Endpoints.const_get(exception.class.name.split('::').last), exception
19
+ @response ||= HttpRequest.get(@uri)
29
20
  end
30
21
  end
31
22
  end
@@ -1,15 +1,15 @@
1
1
  module IndieWeb
2
2
  module Endpoints
3
- class Error < StandardError; end
3
+ class IndieWebEndpointsError < StandardError; end
4
4
 
5
- class ArgumentError < Error; end
5
+ class ArgumentError < IndieWebEndpointsError; end
6
6
 
7
- class ConnectionError < Error; end
7
+ class ConnectionError < IndieWebEndpointsError; end
8
8
 
9
- class InvalidURIError < Error; end
9
+ class InvalidURIError < IndieWebEndpointsError; end
10
10
 
11
- class TimeoutError < Error; end
11
+ class TimeoutError < IndieWebEndpointsError; end
12
12
 
13
- class TooManyRedirectsError < Error; end
13
+ class TooManyRedirectsError < IndieWebEndpointsError; end
14
14
  end
15
15
  end
@@ -0,0 +1,29 @@
1
+ module IndieWeb
2
+ module Endpoints
3
+ class HttpRequest
4
+ # Defaults derived from Webmention specification examples
5
+ # https://www.w3.org/TR/webmention/#limits-on-get-requests
6
+ HTTP_CLIENT_OPTS = {
7
+ follow: {
8
+ max_hops: 20
9
+ },
10
+ headers: {
11
+ accept: '*/*',
12
+ user_agent: 'IndieWeb Endpoint Discovery (https://rubygems.org/gems/indieweb-endpoints)'
13
+ },
14
+ timeout_options: {
15
+ connect_timeout: 5,
16
+ read_timeout: 5
17
+ }
18
+ }.freeze
19
+
20
+ def self.get(uri)
21
+ HTTP::Client.new(HTTP_CLIENT_OPTS).request(:get, uri)
22
+ rescue HTTP::ConnectionError,
23
+ HTTP::TimeoutError,
24
+ HTTP::Redirector::TooManyRedirectsError => exception
25
+ raise IndieWeb::Endpoints.const_get(exception.class.name.split('::').last), exception
26
+ end
27
+ end
28
+ end
29
+ end
@@ -4,13 +4,7 @@ module IndieWeb
4
4
  extend Registerable
5
5
 
6
6
  class BaseParser
7
- # Ultra-orthodox pattern matching allowed values in Link header `rel` parameter
8
- # https://tools.ietf.org/html/rfc8288#section-3.3
9
- REGEXP_REG_REL_TYPE_PATTERN = '[a-z\d][a-z\d\-\.]*'.freeze
10
-
11
- # Liberal pattern matching a string of text between angle brackets
12
- # https://tools.ietf.org/html/rfc5988#section-5.1
13
- REGEXP_TARGET_URI_PATTERN = /^<(.*)>;/.freeze
7
+ attr_reader :response
14
8
 
15
9
  def initialize(response)
16
10
  raise ArgumentError, "response must be an HTTP::Response (given #{response.class.name})" unless response.is_a?(HTTP::Response)
@@ -21,21 +15,42 @@ module IndieWeb
21
15
  def results
22
16
  return unless results_from_http_request
23
17
 
24
- @results ||= Absolutely.to_absolute_uri(base: @response.uri.to_s, relative: results_from_http_request)
18
+ @results ||= Absolutely.to_abs(base: response.uri.to_s, relative: results_from_http_request)
25
19
  rescue Absolutely::InvalidURIError => exception
26
20
  raise InvalidURIError, exception
27
21
  end
28
22
 
29
23
  private
30
24
 
31
- def discrete_link_headers
32
- # Split Link headers with multiple values, flatten the resulting array, and strip whitespace
33
- # https://webmention.rocks/test/19
34
- @discrete_link_headers ||= @response.headers.get('link').map { |header| header.split(',') }.flatten.map(&:strip)
25
+ def results_from_body
26
+ LinkElementParser.new(response, self.class.identifier).results
27
+ end
28
+
29
+ def results_from_headers
30
+ LinkHeaderParser.new(response, self.class.identifier).results
31
+ end
32
+
33
+ def results_from_http_request
34
+ @results_from_http_request ||= results_from_headers || results_from_body || nil
35
+ end
36
+ end
37
+
38
+ class LinkElementParser
39
+ attr_reader :identifier, :response
40
+
41
+ def initialize(response, identifier)
42
+ @response = response
43
+ @identifier = identifier
35
44
  end
36
45
 
46
+ def results
47
+ link_element['href'] if response_is_html && link_element
48
+ end
49
+
50
+ private
51
+
37
52
  def doc
38
- @doc ||= Nokogiri::HTML(@response.body.to_s)
53
+ @doc ||= Nokogiri::HTML(response.body.to_s)
39
54
  end
40
55
 
41
56
  def link_element
@@ -50,42 +65,59 @@ module IndieWeb
50
65
  end
51
66
 
52
67
  def link_elements_css_selector
53
- @link_elements_css_selector ||= %(link[rel~="#{self.class.identifier}"][href])
68
+ @link_elements_css_selector ||= %(link[rel~="#{identifier}"][href]:not([href*="#"]))
54
69
  end
55
70
 
56
- def link_header
57
- @link_header ||= link_headers.shift
71
+ def response_is_html
72
+ @response_is_html ||= response.mime_type == 'text/html'
58
73
  end
74
+ end
59
75
 
60
- def link_headers
61
- # Reduce Link headers to those with valid `rel` attribute
62
- @link_headers ||= discrete_link_headers.find_all { |header| header.match?(regexp_rel_paramater_pattern) }
63
- end
76
+ class LinkHeaderParser
77
+ # Ultra-orthodox pattern matching allowed values in Link header `rel` parameter
78
+ # https://tools.ietf.org/html/rfc8288#section-3.3
79
+ REGEXP_REG_REL_TYPE_PATTERN = '[a-z\d][a-z\d\-\.]*'.freeze
64
80
 
65
- def regexp_rel_paramater_pattern
66
- # Ultra-orthodox pattern matching Link header `rel` parameter including a matching identifier value
67
- # https://www.w3.org/TR/webmention/#sender-discovers-receiver-webmention-endpoint
68
- @regexp_rel_paramater_pattern ||= /(?:;|\s)rel="?(?:#{REGEXP_REG_REL_TYPE_PATTERN}+\s)?#{self.class.identifier}(?:\s#{REGEXP_REG_REL_TYPE_PATTERN})?"?/
69
- end
81
+ # Liberal pattern capturing a string of text (excepting the octothorp) between angle brackets
82
+ # https://tools.ietf.org/html/rfc5988#section-5.1
83
+ REGEXP_TARGET_URI_PATTERN = '^<(.[^#]*)>;'.freeze
70
84
 
71
- def results_from_body
72
- link_element['href'] if response_is_html && link_element
85
+ attr_reader :identifier, :response
86
+
87
+ def initialize(response, identifier)
88
+ @response = response
89
+ @identifier = identifier
73
90
  end
74
91
 
75
- def results_from_headers
92
+ def results
76
93
  return unless link_header
77
94
 
78
- endpoint_match_data = link_header.match(REGEXP_TARGET_URI_PATTERN)
95
+ endpoint_match_data = link_header.match(/#{REGEXP_TARGET_URI_PATTERN}/)
79
96
 
80
97
  return endpoint_match_data[1] if endpoint_match_data
81
98
  end
82
99
 
83
- def response_is_html
84
- @response_is_html ||= @response.mime_type == 'text/html'
100
+ private
101
+
102
+ def discrete_link_headers
103
+ # Split Link headers with multiple values, flatten the resulting array, and strip whitespace
104
+ # https://webmention.rocks/test/19
105
+ @discrete_link_headers ||= response.headers.get('link').map { |header| header.split(',') }.flatten.map(&:strip)
85
106
  end
86
107
 
87
- def results_from_http_request
88
- @results_from_http_request ||= results_from_headers || results_from_body || nil
108
+ def link_header
109
+ @link_header ||= link_headers.shift
110
+ end
111
+
112
+ def link_headers
113
+ # Reduce Link headers to those with valid `rel` attribute
114
+ @link_headers ||= discrete_link_headers.find_all { |header| header.match?(/#{REGEXP_TARGET_URI_PATTERN}\s*#{regexp_rel_paramater_pattern}/) }
115
+ end
116
+
117
+ def regexp_rel_paramater_pattern
118
+ # Ultra-orthodox pattern matching Link header `rel` parameter including a matching identifier value
119
+ # https://www.w3.org/TR/webmention/#sender-discovers-receiver-webmention-endpoint
120
+ @regexp_rel_paramater_pattern ||= %(rel="?(?:#{REGEXP_REG_REL_TYPE_PATTERN}+\s)?#{identifier}(?:\s#{REGEXP_REG_REL_TYPE_PATTERN})?"?)
89
121
  end
90
122
  end
91
123
  end
@@ -0,0 +1,13 @@
1
+ module IndieWeb
2
+ module Endpoints
3
+ module Parsers
4
+ class MicrosubParser < BaseParser
5
+ def self.identifier
6
+ :microsub
7
+ end
8
+
9
+ Parsers.register(self)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -11,7 +11,7 @@ module IndieWeb
11
11
  def results
12
12
  return unless results_from_http_request.any?
13
13
 
14
- @results ||= results_from_http_request.map { |endpoint| Absolutely.to_absolute_uri(base: @response.uri.to_s, relative: endpoint) }.uniq.sort
14
+ @results ||= results_from_http_request.map { |endpoint| Absolutely.to_abs(base: response.uri.to_s, relative: endpoint) }.uniq.sort
15
15
  rescue Absolutely::InvalidURIError => exception
16
16
  raise InvalidURIError, exception
17
17
  end
@@ -19,10 +19,26 @@ module IndieWeb
19
19
  private
20
20
 
21
21
  def results_from_body
22
- link_elements.map { |element| element['href'] } if response_is_html && link_elements.any?
22
+ RedirectUriLinkElementParser.new(response, self.class.identifier).results
23
23
  end
24
24
 
25
25
  def results_from_headers
26
+ RedirectUriLinkHeaderParser.new(response, self.class.identifier).results
27
+ end
28
+
29
+ def results_from_http_request
30
+ @results_from_http_request ||= [results_from_headers, results_from_body].flatten.compact
31
+ end
32
+ end
33
+
34
+ class RedirectUriLinkElementParser < LinkElementParser
35
+ def results
36
+ link_elements.map { |element| element['href'] } if response_is_html && link_elements.any?
37
+ end
38
+ end
39
+
40
+ class RedirectUriLinkHeaderParser < LinkHeaderParser
41
+ def results
26
42
  return unless link_headers.any?
27
43
 
28
44
  link_headers.map do |header|
@@ -31,10 +47,6 @@ module IndieWeb
31
47
  endpoint_match_data[1] if endpoint_match_data
32
48
  end
33
49
  end
34
-
35
- def results_from_http_request
36
- @results_from_http_request ||= [results_from_headers, results_from_body].flatten.compact
37
- end
38
50
  end
39
51
  end
40
52
  end
@@ -10,6 +10,14 @@ module IndieWeb
10
10
 
11
11
  private
12
12
 
13
+ def results_from_body
14
+ WebmentionLinkElementParser.new(response, self.class.identifier).results
15
+ end
16
+ end
17
+
18
+ class WebmentionLinkElementParser < LinkElementParser
19
+ private
20
+
13
21
  def link_element
14
22
  # Return first `a` or `link` element with valid `rel` attribute
15
23
  # https://www.w3.org/TR/webmention/#sender-discovers-receiver-webmention-endpoint
@@ -17,7 +25,7 @@ module IndieWeb
17
25
  end
18
26
 
19
27
  def link_elements_css_selector
20
- @link_elements_css_selector ||= %([rel~="#{self.class.identifier}"][href])
28
+ @link_elements_css_selector ||= %([rel~="#{identifier}"][href]:not([href*="#"]))
21
29
  end
22
30
  end
23
31
  end
@@ -1,5 +1,5 @@
1
1
  module IndieWeb
2
2
  module Endpoints
3
- VERSION = '0.3.0'.freeze
3
+ VERSION = '0.5.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: indieweb-endpoints
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Garber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-30 00:00:00.000000000 Z
11
+ date: 2019-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.67.2
61
+ version: 0.68.1
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.67.2
68
+ version: 0.68.1
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop-performance
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '2.0'
145
+ version: '2.1'
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '2.0'
152
+ version: '2.1'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: addressable
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -192,7 +192,7 @@ dependencies:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
194
  version: '1.10'
195
- description: Discover a URL’s IndieAuth, Micropub, and Webmention endpoints.
195
+ description: Discover a URL’s IndieAuth, Micropub, Microsub, and Webmention endpoints.
196
196
  email:
197
197
  - jason@sixtwothree.org
198
198
  executables: []
@@ -220,9 +220,11 @@ files:
220
220
  - lib/indieweb/endpoints.rb
221
221
  - lib/indieweb/endpoints/client.rb
222
222
  - lib/indieweb/endpoints/exceptions.rb
223
+ - lib/indieweb/endpoints/http_request.rb
223
224
  - lib/indieweb/endpoints/parsers.rb
224
225
  - lib/indieweb/endpoints/parsers/authorization_endpoint_parser.rb
225
226
  - lib/indieweb/endpoints/parsers/micropub_parser.rb
227
+ - lib/indieweb/endpoints/parsers/microsub_parser.rb
226
228
  - lib/indieweb/endpoints/parsers/redirect_uri_parser.rb
227
229
  - lib/indieweb/endpoints/parsers/token_endpoint_parser.rb
228
230
  - lib/indieweb/endpoints/parsers/webmention_parser.rb
@@ -231,7 +233,9 @@ files:
231
233
  homepage: https://github.com/indieweb/indieweb-endpoints-ruby
232
234
  licenses:
233
235
  - MIT
234
- metadata: {}
236
+ metadata:
237
+ bug_tracker_uri: https://github.com/indieweb/indieweb-endpoints-ruby/issues
238
+ changelog_uri: https://github.com/indieweb/indieweb-endpoints-ruby/blob/v0.5.0/CHANGELOG.md
235
239
  post_install_message:
236
240
  rdoc_options: []
237
241
  require_paths:
@@ -253,5 +257,5 @@ requirements: []
253
257
  rubygems_version: 3.0.3
254
258
  signing_key:
255
259
  specification_version: 4
256
- summary: Discover a URL’s IndieAuth, Micropub, and Webmention endpoints.
260
+ summary: Discover a URL’s IndieAuth, Micropub, Microsub, and Webmention endpoints.
257
261
  test_files: []