Skip to content

Commit

Permalink
Handle HTTP redirection.
Browse files Browse the repository at this point in the history
  • Loading branch information
toddsundsted committed May 30, 2020
1 parent 2d13bbc commit 8939c43
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 18 deletions.
7 changes: 7 additions & 0 deletions spec/web_finger/client_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class HTTP::Client
raise Socket::Addrinfo::Error.new(LibC::EAI_NONAME, "No address found", url.host)
end
case url.query || url.path
when /redirect/
yield HTTP::Client::Response.new(302, headers: HTTP::Headers{"Location" => "https://elsewhere/"})
when /not-found/
yield HTTP::Client::Response.new(404)
when /internal-server-error/
Expand Down Expand Up @@ -128,6 +130,11 @@ Spectator.describe WebFinger::Client do
end
end

it "redirects" do
WebFinger::Client.query("acct:redirect@example.com")
expect(HTTP::Client.history.map(&.host)).to contain("elsewhere")
end

it "makes an HTTP request to the account domain" do
WebFinger::Client.query("acct:foobar@example.com")
expect(HTTP::Client.history.map(&.host)).to contain("example.com")
Expand Down
52 changes: 34 additions & 18 deletions src/web_finger/client.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ module WebFinger
class NotFoundError < Error
end

# Redirection failed.
class RedirectionError < Error
end

# The client.
module Client
# Returns the result of querying for the specified account.
Expand All @@ -20,10 +24,11 @@ module WebFinger
# w = WebFinger.query("acct:toddsundsted@epiktistes.com") # => #<WebFinger::Result:0x108d...>
# w.link("http://webfinger.net/rel/profile-page").href # => "https://epiktistes.com/@toddsundsted"
#
# Raises `WebFinger::NotFoundError` if the account does not
# exist. Otherwise, returns `WebFinger::Result`.
# Raises `WebFinger::NotFoundError` if the account does not exist
# and `WebFinger::RedirectionError` if redirection failed.
# Otherwise, returns `WebFinger::Result`.
#
def self.query(account)
def self.query(account, attempts = 10)
unless account =~ /^([^@]+)@([^@]+)$/
raise Error.new("invalid account: #{account}")
end
Expand All @@ -38,25 +43,36 @@ module WebFinger

url = template.gsub("{uri}", URI.encode_www_form(account))

HTTP::Client.get(url) do |response|
case (code = response.status_code)
when 200
mt = response.mime_type.try(&.media_type)
if mt =~ /xml/
Result.from_xml(response.body_io)
elsif mt =~ /json/
Result.from_json(response.body_io)
elsif response.body_io.peek.try(&.first) == 123 # sniff for '{'
Result.from_json(response.body_io)
attempts.times do |i|
HTTP::Client.get(url) do |response|
case (code = response.status_code)
when 200
mt = response.mime_type.try(&.media_type)
result =
if mt =~ /xml/
Result.from_xml(response.body_io)
elsif mt =~ /json/
Result.from_json(response.body_io)
elsif response.body_io.peek.try(&.first) == 123 # sniff for '{'
Result.from_json(response.body_io)
else
Result.from_xml(response.body_io)
end
return result
when 300, 301, 302, 303, 307, 308
if (tmp = response.headers["Location"]?) && (url = tmp)
next
else
break
end
when 404
raise NotFoundError.new("not found [#{code}]: #{url}")
else
Result.from_xml(response.body_io)
raise Error.new("error [#{code}]: #{url}")
end
when 404
raise NotFoundError.new("not found [#{code}]: #{url}")
else
raise Error.new("error [#{code}]: #{url}")
end
end
raise RedirectionError.new("redirection failed: #{url}")
rescue ex : Socket::Addrinfo::Error
raise NotFoundError.new(ex.message)
end
Expand Down

0 comments on commit 8939c43

Please sign in to comment.