indieweb-endpoints 7.0.0 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 151e40ea1ac993997ee70da6c2f997609fb1311f33ab4f10d9090d76a555c3ec
4
- data.tar.gz: 73547ed72b54f2c2b954bc89df1b697bd22fbc02ea59104b6dc841b7ec9ab6ab
3
+ metadata.gz: ee2f8e43786e217e42c08df7c1aeec438bd56aa9156d431c49bb8163216b6df7
4
+ data.tar.gz: 8336092d579bee80500f14a0f278e584c70d20f5bd51cf46012e080fc64af944
5
5
  SHA512:
6
- metadata.gz: 34e13013f71ae9d4ea89fbf1ba2a40619579023203a95a72b30c552b80ce3442e13d4eceeef4eaeceed074f3e9e39300a0b45c42e50a16c072a72f9f863b8809
7
- data.tar.gz: 2f3c6b0e7267e69096f348210bf087b171c2d4acb64577bcc1a9440b0367655c85c62c23d837f054984389b4b484e39daab085db4112bd2f5777b3ce0cd33534
6
+ metadata.gz: 56fa47965f839f37ce65fb1d2d3445265c66b865d2d85486b45f3306b6e5c13b1e4c98d301f2507ebe72ed279e2dc5e1449c891fdbc4a6746ff9ca088f8b621d
7
+ data.tar.gz: 320cfd2300bf0ae34d69031bb78eaabf0526105b5ed761f9c6f607585047ee81a72a347e9998cd06f366e636321d1ac32f345b1017ed8d634aa0620d65145a28
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 7.2.0 / 2022-10-04
4
+
5
+ - Add support for `indieauth-metadata` endpoint (35cc950)
6
+ - Switch from pry-byebug to Ruby's debug gem (7ad8925)
7
+ - Update development Ruby version to 2.6.10 (f105752)
8
+
9
+ ## 7.1.0 / 2022-03-08
10
+
11
+ - Refactor gem code (eba8115)
12
+ - Refactor specs (5b92119)
13
+ - Rescue from `OpenSSL::SSL::SSLError` (4ea38e5)
14
+
3
15
  ## 7.0.0 / 2022-01-06
4
16
 
5
17
  - Update runtime dependency versions (5c9430f)
data/CONTRIBUTING.md CHANGED
@@ -8,9 +8,9 @@ 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.6.9 and is additionally tested against Ruby 2.7, 3.0, and 3.1 using [GitHub Actions](https://github.com/indieweb/indieweb-endpoints-ruby/actions).
11
+ indieweb-endpoints-ruby is developed using Ruby 2.6.10 and is additionally tested against Ruby 2.7, 3.0, and 3.1 using [GitHub Actions](https://github.com/indieweb/indieweb-endpoints-ruby/actions).
12
12
 
13
- Before making changes to indieweb-endpoints-ruby, you'll want to install Ruby 2.6.9. 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.6.9 using your method of choice, install the project's gems by running:
13
+ Before making changes to indieweb-endpoints-ruby, you'll want to install Ruby 2.6.10. 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.6.10 using your method of choice, install the project's gems by running:
14
14
 
15
15
  ```sh
16
16
  bundle install
@@ -22,7 +22,7 @@ bundle install
22
22
  1. Install development dependencies as outlined above.
23
23
  1. Create a feature branch for the code changes you're looking to make: `git checkout -b my-new-feature`.
24
24
  1. _Write some code!_
25
- 1. If your changes would benefit from testing, add the necessary tests and verify everything passes by running `bin/ci`.
25
+ 1. If your changes would benefit from testing, add the necessary tests and verify everything passes by running `bundle exec rspec`.
26
26
  1. Commit your changes: `git commit -am 'Add some new feature or fix some issue'`. _(See [this excellent article](https://chris.beams.io/posts/git-commit/) for tips on writing useful Git commit messages.)_
27
27
  1. Push the branch to your fork: `git push -u origin my-new-feature`.
28
28
  1. Create a new [pull request][pulls] and we'll review your changes.
data/README.md CHANGED
@@ -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.6 (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.6.9 and is additionally tested against Ruby 2.7, 3.0, and 3.1 using [GitHub Actions](https://github.com/indieweb/indieweb-endpoints-ruby/actions).
21
+ indieweb-endpoints-ruby is developed using Ruby 2.6.10 and is additionally tested against Ruby 2.7, 3.0, and 3.1 using [GitHub Actions](https://github.com/indieweb/indieweb-endpoints-ruby/actions).
22
22
 
23
23
  ## Installation
24
24
 
@@ -46,7 +46,7 @@ With indieweb-endpoints-ruby added to your project's `Gemfile` and installed, yo
46
46
  require 'indieweb/endpoints'
47
47
 
48
48
  IndieWeb::Endpoints.get('https://aaronparecki.com')
49
- #=> { authorization_endpoint: "https://aaronparecki.com/auth", micropub: "https://aaronparecki.com/micropub", microsub: "https://aperture.p3k.io/microsub/1", redirect_uri: nil, token_endpoint: "https://aaronparecki.com/auth/token", webmention: "https://webmention.io/aaronpk/webmention" }
49
+ #=> { authorization_endpoint: "https://aaronparecki.com/auth", "indieauth-metadata": "https://aaronparecki.com/.well-known/oauth-authorization-server", micropub: "https://aaronparecki.com/micropub", microsub: "https://aperture.p3k.io/microsub/1", redirect_uri: nil, token_endpoint: "https://aaronparecki.com/auth/token", webmention: "https://webmention.io/aaronpk/webmention" }
50
50
  ```
51
51
 
52
52
  This example will search `https://aaronparecki.com` for valid IndieAuth, Micropub, and Webmention endpoints and return a `Hash` of results. Each key in the returned `Hash` will have a value of either a `String` representing a URL or `nil`. The `redirect_uri` key's value will be either an `Array` or `nil` since a given URL may register multiple callback URLs.
@@ -59,7 +59,7 @@ Should the need arise, you may work with the `IndieWeb::Endpoints::Client` class
59
59
  require 'indieweb/endpoints'
60
60
 
61
61
  client = IndieWeb::Endpoints::Client.new('https://aaronparecki.com')
62
- #=> #<IndieWeb::Endpoints::Client url: "https://aaronparecki.com">
62
+ #=> #<IndieWeb::Endpoints::Client uri: "https://aaronparecki.com">
63
63
 
64
64
  client.response
65
65
  #=> #<HTTP::Response/1.1 200 OK {…}>
@@ -80,6 +80,10 @@ From [httprb/http](https://github.com/httprb/http):
80
80
 
81
81
  - `IndieWeb::Endpoints::HttpError`
82
82
 
83
+ From the Ruby Standard Library's [`OpenSSL::SSL::SSLError`](https://ruby-doc.org/stdlib-2.6.10/libdoc/openssl/rdoc/OpenSSL/SSL/SSLError.html):
84
+
85
+ - `IndieWeb::Endpoints::SSLError`
86
+
83
87
  ## Contributing
84
88
 
85
89
  Interested in helping improve indieweb-endpoints-ruby? Awesome! Your help is greatly appreciated. See [CONTRIBUTING.md](https://github.com/indieweb/indieweb-endpoints-ruby/blob/main/CONTRIBUTING.md) for details.
@@ -27,8 +27,7 @@ Gem::Specification.new do |spec|
27
27
  'rubygems_mfa_required' => 'true'
28
28
  }
29
29
 
30
- spec.add_runtime_dependency 'addressable', '~> 2.8'
31
30
  spec.add_runtime_dependency 'http', '~> 5.0'
32
31
  spec.add_runtime_dependency 'link-header-parser', '~> 4.0'
33
- spec.add_runtime_dependency 'nokogiri', '~> 1.12'
32
+ spec.add_runtime_dependency 'nokogiri', '~> 1.13'
34
33
  end
@@ -8,43 +8,50 @@ module IndieWeb
8
8
  user_agent: 'IndieWeb Endpoint Discovery (https://rubygems.org/gems/indieweb-endpoints)'
9
9
  }.freeze
10
10
 
11
- # Create a new client with a URL to parse for IndieWeb endpoints
11
+ # Create a new client with a URL to parse for IndieWeb endpoints.
12
12
  #
13
+ # @example
13
14
  # client = IndieWeb::Endpoints::Client.new('https://aaronparecki.com')
14
15
  #
15
- # @param url [String] an absolute URL
16
+ # @param url [String, HTTP::URI, #to_s] an absolute URL
17
+ # @raise [IndieWeb::Endpoints::InvalidURIError]
16
18
  def initialize(url)
17
- @url = url.to_str
19
+ @uri = HTTP::URI.parse(url.to_s)
20
+ rescue Addressable::URI::InvalidURIError => e
21
+ raise InvalidURIError, e
18
22
  end
19
23
 
20
24
  # @return [String]
21
25
  def inspect
22
- "#<#{self.class.name}:#{format('%#0x', object_id)} url: #{url.inspect}>"
26
+ %(#<#{self.class.name}:#{format('%#0x', object_id)} uri: "#{uri}">)
23
27
  end
24
28
 
29
+ # A Hash of the discovered IndieWeb endpoints from the provided URL.
30
+ #
25
31
  # @return [Hash{Symbol => String, Array, nil}]
26
32
  def endpoints
27
- @endpoints ||= Parsers.registered.transform_values { |parser| parser.new(response).results }
33
+ @endpoints ||= Parser.new(response).results
28
34
  end
29
35
 
30
- # @see https://www.w3.org/TR/webmention/#limits-on-get-requests
36
+ # The +HTTP::Response+ object returned by the provided URL.
31
37
  #
32
38
  # @return [HTTP::Response]
39
+ # @raise [IndieWeb::Endpoints::HttpError, IndieWeb::Endpoints::SSLError]
33
40
  def response
34
- @response ||= HTTP.follow(max_hops: 20).headers(HTTP_HEADERS_OPTS).timeout(connect: 5, read: 5).get(uri)
41
+ @response ||= HTTP.follow(max_hops: 20)
42
+ .headers(HTTP_HEADERS_OPTS)
43
+ .timeout(connect: 5, read: 5)
44
+ .get(uri)
35
45
  rescue HTTP::Error => e
36
46
  raise HttpError, e
47
+ rescue OpenSSL::SSL::SSLError => e
48
+ raise SSLError, e
37
49
  end
38
50
 
39
51
  private
40
52
 
41
- attr_accessor :url
42
-
43
- def uri
44
- @uri ||= Addressable::URI.parse(url)
45
- rescue Addressable::URI::InvalidURIError => e
46
- raise InvalidURIError, e
47
- end
53
+ # @return [HTTP::URI]
54
+ attr_reader :uri
48
55
  end
49
56
  end
50
57
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IndieWeb
4
+ module Endpoints
5
+ # @api private
6
+ class Parser
7
+ # @param response [HTTP::Response]
8
+ def initialize(response)
9
+ @response = response
10
+ end
11
+
12
+ # @return [Hash{Symbol => String, Array<String>, nil}]
13
+ def results
14
+ {
15
+ authorization_endpoint: result_for(:authorization_endpoint),
16
+ 'indieauth-metadata': result_for(:'indieauth-metadata'),
17
+ micropub: result_for(:micropub),
18
+ microsub: result_for(:microsub),
19
+ redirect_uri: results_for(:redirect_uri),
20
+ token_endpoint: result_for(:token_endpoint),
21
+ webmention: result_for(:webmention, %w[link a])
22
+ }
23
+ end
24
+
25
+ private
26
+
27
+ # @return [HTTP::Response]
28
+ attr_reader :response
29
+
30
+ # @return [IndieWeb::Endpoints::ResponseBodyParser]
31
+ def response_body_parser
32
+ @response_body_parser ||= ResponseBodyParser.new(response)
33
+ end
34
+
35
+ # @return [IndieWeb::Endpoints::ResponseHeadersParser]
36
+ def response_headers_parser
37
+ @response_headers_parser ||= ResponseHeadersParser.new(response)
38
+ end
39
+
40
+ # @param identifier [Symbol]
41
+ # @param nodes [Array<String>]
42
+ # @return [String, nil]
43
+ def result_for(identifier, nodes = ['link'])
44
+ results_for(identifier, nodes)&.first
45
+ end
46
+
47
+ # @param identifier [Symbol]
48
+ # @param nodes [Array<String>]
49
+ # @return [Array<String>, nil]
50
+ # @raise [IndieWeb::Endpoints::InvalidURIError]
51
+ def results_for(identifier, nodes = ['link'])
52
+ results_from_request = [
53
+ response_headers_parser.results_for(identifier),
54
+ response_body_parser.results_for(identifier, nodes)
55
+ ].flatten.compact
56
+
57
+ return if results_from_request.none?
58
+
59
+ results_from_request.map { |endpoint| response.uri.join(endpoint).to_s }.uniq.sort
60
+ rescue Addressable::URI::InvalidURIError => e
61
+ raise InvalidURIError, e
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IndieWeb
4
+ module Endpoints
5
+ # @api private
6
+ class ResponseBodyParser
7
+ # @param response [HTTP::Response]
8
+ def initialize(response)
9
+ @body = response.body.to_s
10
+ @mime_type = response.mime_type
11
+ @uri = response.uri
12
+ end
13
+
14
+ # @param identifier [Symbol]
15
+ # @param nodes [Array<String>]
16
+ # @return [Array<string>, nil]
17
+ def results_for(identifier, nodes = ['link'])
18
+ return unless mime_type == 'text/html'
19
+
20
+ # Reject endpoints that contain a fragment identifier
21
+ selectors = nodes.map { |node| %(#{node}[rel~="#{identifier}"][href]:not([href*="#"])) }.join(',')
22
+
23
+ parsed_body.css(selectors).map { |element| element['href'] }
24
+ end
25
+
26
+ private
27
+
28
+ # @return [String]
29
+ attr_reader :body
30
+
31
+ # @return [String]
32
+ attr_reader :mime_type
33
+
34
+ # @return [HTTP::URI]
35
+ attr_reader :uri
36
+
37
+ # @return [Nokogiri::HTML5::Document]
38
+ def parsed_body
39
+ @parsed_body ||= Nokogiri::HTML5(body)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IndieWeb
4
+ module Endpoints
5
+ # @api private
6
+ class ResponseHeadersParser
7
+ # @param response [HTTP::Response]
8
+ def initialize(response)
9
+ @headers = response.headers.get('link')
10
+ @uri = response.uri
11
+ end
12
+
13
+ # @param identifier [Symbol]
14
+ # @return [Array<String>, nil]
15
+ def results_for(identifier)
16
+ return unless parsed_headers.key?(identifier)
17
+
18
+ # Reject endpoints that contain a fragment identifier
19
+ parsed_headers[identifier].reject { |header| HTTP::URI.parse(header.target_uri).fragment }.map(&:target_uri)
20
+ end
21
+
22
+ private
23
+
24
+ # @return [Array<String>]
25
+ attr_reader :headers
26
+
27
+ # @return [HTTP::URI]
28
+ attr_reader :uri
29
+
30
+ # @return [Hash{Symbol => Array<LinkHeaderParser::LinkHeader>}]
31
+ def parsed_headers
32
+ @parsed_headers ||= LinkHeaderParser.parse(headers, base: uri).group_by_relation_type
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module IndieWeb
4
4
  module Endpoints
5
- VERSION = '7.0.0'
5
+ VERSION = '7.2.0'
6
6
  end
7
7
  end
@@ -1,34 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'addressable/uri'
4
3
  require 'http'
5
4
  require 'link-header-parser'
6
5
  require 'nokogiri'
7
6
 
8
7
  require_relative 'endpoints/version'
9
- require_relative 'endpoints/exceptions'
10
-
11
- require_relative 'endpoints/services/response_parser_service'
12
8
 
13
9
  require_relative 'endpoints/client'
14
- require_relative 'endpoints/parsers'
15
-
16
- require_relative 'endpoints/parsers/base_parser'
17
- require_relative 'endpoints/parsers/authorization_endpoint_parser'
18
- require_relative 'endpoints/parsers/micropub_parser'
19
- require_relative 'endpoints/parsers/microsub_parser'
20
- require_relative 'endpoints/parsers/redirect_uri_parser'
21
- require_relative 'endpoints/parsers/token_endpoint_parser'
22
- require_relative 'endpoints/parsers/webmention_parser'
10
+ require_relative 'endpoints/parser'
11
+ require_relative 'endpoints/response_body_parser'
12
+ require_relative 'endpoints/response_headers_parser'
23
13
 
24
14
  module IndieWeb
25
15
  module Endpoints
26
- # Discover a URL's IndieAuth, Micropub, Microsub, and Webmention endpoints
16
+ class Error < StandardError; end
17
+ class HttpError < Error; end
18
+ class InvalidURIError < Error; end
19
+ class SSLError < Error; end
20
+
21
+ # Discover a URL's IndieAuth, Micropub, Microsub, and Webmention endpoints.
22
+ #
23
+ # Convenience method for {IndieWeb::Endpoints::Client#endpoints}.
27
24
  #
25
+ # @example
28
26
  # IndieWeb::Endpoints.get('https://aaronparecki.com')
29
27
  #
30
- # @param url [String] an absolute URL
31
- # @return [Hash{Symbol => String, Array, nil}]
28
+ # @param (see IndieWeb::Endpoints::Client#endpoints)
29
+ # @return (see IndieWeb::Endpoints::Client#endpoints)
32
30
  def self.get(url)
33
31
  Client.new(url).endpoints
34
32
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: indieweb-endpoints
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.0
4
+ version: 7.2.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: 2022-01-06 00:00:00.000000000 Z
11
+ date: 2022-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: addressable
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.8'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.8'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: http
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +44,14 @@ dependencies:
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '1.12'
47
+ version: '1.13'
62
48
  type: :runtime
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '1.12'
54
+ version: '1.13'
69
55
  description: Discover a URL’s IndieAuth, Micropub, Microsub, and Webmention endpoints.
70
56
  email:
71
57
  - jason@sixtwothree.org
@@ -81,23 +67,16 @@ files:
81
67
  - indieweb-endpoints.gemspec
82
68
  - lib/indieweb/endpoints.rb
83
69
  - lib/indieweb/endpoints/client.rb
84
- - lib/indieweb/endpoints/exceptions.rb
85
- - lib/indieweb/endpoints/parsers.rb
86
- - lib/indieweb/endpoints/parsers/authorization_endpoint_parser.rb
87
- - lib/indieweb/endpoints/parsers/base_parser.rb
88
- - lib/indieweb/endpoints/parsers/micropub_parser.rb
89
- - lib/indieweb/endpoints/parsers/microsub_parser.rb
90
- - lib/indieweb/endpoints/parsers/redirect_uri_parser.rb
91
- - lib/indieweb/endpoints/parsers/token_endpoint_parser.rb
92
- - lib/indieweb/endpoints/parsers/webmention_parser.rb
93
- - lib/indieweb/endpoints/services/response_parser_service.rb
70
+ - lib/indieweb/endpoints/parser.rb
71
+ - lib/indieweb/endpoints/response_body_parser.rb
72
+ - lib/indieweb/endpoints/response_headers_parser.rb
94
73
  - lib/indieweb/endpoints/version.rb
95
74
  homepage: https://github.com/indieweb/indieweb-endpoints-ruby
96
75
  licenses:
97
76
  - MIT
98
77
  metadata:
99
78
  bug_tracker_uri: https://github.com/indieweb/indieweb-endpoints-ruby/issues
100
- changelog_uri: https://github.com/indieweb/indieweb-endpoints-ruby/blob/v7.0.0/CHANGELOG.md
79
+ changelog_uri: https://github.com/indieweb/indieweb-endpoints-ruby/blob/v7.2.0/CHANGELOG.md
101
80
  rubygems_mfa_required: 'true'
102
81
  post_install_message:
103
82
  rdoc_options: []
@@ -117,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
96
  - !ruby/object:Gem::Version
118
97
  version: '0'
119
98
  requirements: []
120
- rubygems_version: 3.2.33
99
+ rubygems_version: 3.3.12
121
100
  signing_key:
122
101
  specification_version: 4
123
102
  summary: Discover a URL’s IndieAuth, Micropub, Microsub, and Webmention endpoints.
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- class Error < StandardError; end
6
-
7
- class ArgumentError < Error; end
8
-
9
- class HttpError < Error; end
10
-
11
- class InvalidURIError < Error; end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Parsers
6
- class AuthorizationEndpointParser < BaseParser
7
- @identifier = :authorization_endpoint
8
-
9
- Parsers.register(self)
10
- end
11
- end
12
- end
13
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Parsers
6
- class BaseParser
7
- class << self
8
- attr_reader :identifier
9
- end
10
-
11
- # @param response [HTTP::Response]
12
- def initialize(response)
13
- raise ArgumentError, "response must be an HTTP::Response (given #{response.class.name})" unless response.is_a?(HTTP::Response)
14
-
15
- @response = response
16
- end
17
-
18
- # @return [String]
19
- def results
20
- mapped_results.shift
21
- end
22
-
23
- private
24
-
25
- attr_reader :response
26
-
27
- def mapped_results
28
- @mapped_results ||= results_from_http_request.map { |endpoint| Addressable::URI.join(response.uri, endpoint).to_s }.uniq.sort
29
- rescue Addressable::URI::InvalidURIError => e
30
- raise InvalidURIError, e
31
- end
32
-
33
- def parsed_response_body
34
- @parsed_response_body ||= Nokogiri::HTML(response.body.to_s)
35
- end
36
-
37
- def parsed_response_headers
38
- @parsed_response_headers ||= LinkHeaderParser.parse(response.headers.get('link'), base: response.uri)
39
- end
40
-
41
- def results_from_body
42
- return if response.mime_type != 'text/html'
43
-
44
- Services::ResponseParserService.parse_body(parsed_response_body, self.class.identifier)
45
- end
46
-
47
- def results_from_headers
48
- return if parsed_response_headers.none?
49
-
50
- Services::ResponseParserService.parse_headers(parsed_response_headers.group_by_relation_type, self.class.identifier)
51
- end
52
-
53
- def results_from_http_request
54
- @results_from_http_request ||= [results_from_headers, results_from_body].flatten.compact
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Parsers
6
- class MicropubParser < BaseParser
7
- @identifier = :micropub
8
-
9
- Parsers.register(self)
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Parsers
6
- class MicrosubParser < BaseParser
7
- @identifier = :microsub
8
-
9
- Parsers.register(self)
10
- end
11
- end
12
- end
13
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Parsers
6
- class RedirectUriParser < BaseParser
7
- @identifier = :redirect_uri
8
-
9
- Parsers.register(self)
10
-
11
- # @return [Array<String>, nil]
12
- def results
13
- return if mapped_results.none?
14
-
15
- mapped_results
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Parsers
6
- class TokenEndpointParser < BaseParser
7
- @identifier = :token_endpoint
8
-
9
- Parsers.register(self)
10
- end
11
- end
12
- end
13
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Parsers
6
- class WebmentionParser < BaseParser
7
- @identifier = :webmention
8
-
9
- Parsers.register(self)
10
-
11
- private
12
-
13
- def results_for_node(node)
14
- Services::ResponseParserService.parse_body(parsed_response_body, self.class.identifier, node)
15
- end
16
-
17
- # https://www.w3.org/TR/webmention/#sender-discovers-receiver-webmention-endpoint
18
- def results_from_body
19
- @results_from_body ||= [results_for_node('link'), results_for_node('a')].flatten.compact
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Parsers
6
- def self.register(klass)
7
- registered[klass.identifier] = klass
8
- end
9
-
10
- def self.registered
11
- @registered ||= {}
12
- end
13
- end
14
- end
15
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module IndieWeb
4
- module Endpoints
5
- module Services
6
- class ResponseParserService
7
- # @param body [Nokogiri::HTML::Document]
8
- # @param identifier [Symbol]
9
- # @return [Array<String>]
10
- def self.parse_body(body, identifier, node = 'link')
11
- # Reject endpoints that contain a fragment identifier
12
- body.css(%(#{node}[rel~="#{identifier}"][href]:not([href*="#"]))).map { |element| element['href'] }
13
- end
14
-
15
- # @param headers [Hash{Symbol => Array<LinkHeaderParser::LinkHeader}]
16
- # @param identifier [Symbol]
17
- # @return [Array<String>, nil]
18
- def self.parse_headers(headers, identifier)
19
- return unless headers.key?(identifier)
20
-
21
- # Reject endpoints that contain a fragment identifier
22
- headers[identifier].reject { |header| Addressable::URI.parse(header.target_uri).fragment }.map(&:target_uri)
23
- end
24
- end
25
- end
26
- end
27
- end