class IndieAuthDiscovery::URL

Canonicalization for IndieAuth client and user profile URLs.

Constants

FARADAY_ERRORS
PERMANENT_REDIRECTS

Attributes

canonical_url[R]
original_url[R]
redirects[R]

Public Class Methods

canonicalize(original_url) click to toggle source
# File lib/indieauth_discovery/url.rb, line 20
def self.canonicalize(original_url)
  url = new(original_url)
  url.canonicalize
  url
end
new(original_url) click to toggle source
# File lib/indieauth_discovery/url.rb, line 14
def initialize(original_url)
  @original_url = original_url.to_s
  @canonical_url = original_url.to_s
  @redirects = []
end

Public Instance Methods

canonicalize() click to toggle source

Canonicalizes and verifies the URL.

@see indieauth.spec.indieweb.org/#user-profile-url @see indieauth.spec.indieweb.org/#client-identifier

# File lib/indieauth_discovery/url.rb, line 30
def canonicalize
  canonical = normalize_url(original_url)
  canonical, verify_response = verify_url(canonical)
  canonical = ensure_path(canonical)
  canonical = follow_redirects(canonical, verify_response)

  @canonical_url = canonical
rescue URI::InvalidURIError, *FARADAY_ERRORS
  raise_invalid_url_error(original_url)
end
to_s() click to toggle source

Returns the canonical URL as a string.

# File lib/indieauth_discovery/url.rb, line 42
def to_s
  @canonical_url
end
to_uri() click to toggle source

Returns the canonical URL as a URI.

# File lib/indieauth_discovery/url.rb, line 47
def to_uri
  URI.parse(@canonical_url)
end

Private Instance Methods

check_url?(uri) click to toggle source
# File lib/indieauth_discovery/url.rb, line 82
def check_url?(uri)
  response = Faraday.head(uri)
  return false unless response.status < 400

  response
rescue *FARADAY_ERRORS
  nil
end
ensure_path(uri) click to toggle source
# File lib/indieauth_discovery/url.rb, line 91
def ensure_path(uri)
  return uri unless URI.parse(uri).path == ''

  "#{uri}/"
end
follow_redirects(uri, response) click to toggle source

@see indieauth.spec.indieweb.org/#redirect-examples

# File lib/indieauth_discovery/url.rb, line 98
def follow_redirects(uri, response)
  return uri unless [300, 301, 302, 303, 304, 307, 308].include?(response.status)

  redirector(uri).head
  redirects.each do |redirect|
    status = redirect[:status]
    break unless PERMANENT_REDIRECTS.include?(status)

    uri = redirect[:url] if PERMANENT_REDIRECTS.include?(status)
  end

  uri
end
http_uri?(uri) click to toggle source
# File lib/indieauth_discovery/url.rb, line 78
def http_uri?(uri)
  uri.is_a?(URI::HTTPS) || uri.is_a?(URI::HTTP)
end
normalize_url(url) click to toggle source
# File lib/indieauth_discovery/url.rb, line 57
def normalize_url(url)
  URI.parse(url).normalize
end
raise_invalid_url_error(url) click to toggle source
# File lib/indieauth_discovery/url.rb, line 124
def raise_invalid_url_error(url)
  raise InvalidURLError.new(:invalid_url, 'URL must begin with http:// or https://', url)
end
redirect_callback(old_env, new_env) click to toggle source
# File lib/indieauth_discovery/url.rb, line 120
def redirect_callback(old_env, new_env)
  redirects << { url: new_env.url.to_s, status: old_env.status }
end
redirector(uri) click to toggle source
# File lib/indieauth_discovery/url.rb, line 112
def redirector(uri)
  @redirector ||=
    Faraday.new(url: uri) do |faraday|
      faraday.use(FaradayMiddleware::FollowRedirects, callback: method(:redirect_callback))
      faraday.adapter(Faraday.default_adapter)
    end
end
verify_url(uri) click to toggle source

@see indieauth.spec.indieweb.org/#url-canonicalization

# File lib/indieauth_discovery/url.rb, line 62
def verify_url(uri)
  if http_uri?(uri) && (last_response = check_url?(uri))
    # Use the URL as-is if its already HTTP(S) and is available
    [uri.to_s, last_response]
  elsif (last_response = check_url?(URI.parse("https://#{uri}")))
    # If no scheme was given (e.g. example.com), try HTTPS
    ["https://#{uri}", last_response]
  elsif (last_response = check_url?(URI.parse("http://#{uri}")))
    # Try HTTP if HTTPS is not available
    ["http://#{uri}", last_response]
  else
    # The URL is considered invalid if none of the above work
    raise_invalid_url_error(uri)
  end
end