Skip to content

Commit c9231d7

Browse files
committed
Move redirect support to Response.
1 parent 7a89c81 commit c9231d7

File tree

6 files changed

+60
-12
lines changed

6 files changed

+60
-12
lines changed

lib/feedkit.rb

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
require "cgi"
99
require "rchardet"
1010
require "addressable"
11+
require "ostruct"
1112

1213
require "feedkit/core_ext/try"
1314
require "feedkit/feedjira_extension"
@@ -16,6 +17,7 @@
1617
require "feedkit/detect_encoding"
1718
require "feedkit/errors"
1819
require "feedkit/basic_auth"
20+
require "feedkit/redirect"
1921
require "feedkit/response"
2022
require "feedkit/request"
2123
require "feedkit/curl"

lib/feedkit/curl.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def download
2828
out, _, status = Open3.capture3(command % params)
2929
if status.success?
3030
response = CurlResponse.new(@parsed_url.url)
31-
Response.new(tempfile: tempfile, response: response, parsed_url: @parsed_url)
31+
Response.new(tempfile: tempfile, response: response, parsed_url: @parsed_url, redirects: [])
3232
else
3333
raise ServerError.new(HTTP::Response::Status.new(500).to_s, nil)
3434
end

lib/feedkit/redirect.rb

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Feedkit
2+
class Redirect
3+
PERMANENT_REDIRECTS = [301, 308].to_set.freeze
4+
5+
attr_reader :status, :from, :to
6+
7+
def initialize(status:, from:, to:)
8+
@status = status
9+
@from = from
10+
@to = to
11+
end
12+
13+
def permanent?
14+
PERMANENT_REDIRECTS.include?(@status)
15+
end
16+
end
17+
end

lib/feedkit/request.rb

+10-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def initialize(url, on_redirect: nil, auto_inflate: true, username: nil, passwor
2323
@user_agent = user_agent
2424
@last_modified = last_modified
2525
@etag = etag
26+
@redirects = []
2627
end
2728

2829
def download
@@ -32,7 +33,7 @@ def download
3233

3334
response = request
3435
if response.status.code == 304
35-
Response.new(tempfile: Tempfile.new, response: response, parsed_url: @parsed_url)
36+
Response.new(tempfile: Tempfile.new, response: response, parsed_url: @parsed_url, redirects: @redirects)
3637
else
3738
download_to_file(response)
3839
end
@@ -59,7 +60,7 @@ def download_to_file(response)
5960
tempfile.open # flush written content
6061
tempfile.rewind
6162

62-
Response.new(tempfile: tempfile, response: response, parsed_url: @parsed_url)
63+
Response.new(tempfile: tempfile, response: response, parsed_url: @parsed_url, redirects: @redirects)
6364
rescue
6465
tempfile&.close
6566
raise
@@ -68,7 +69,7 @@ def download_to_file(response)
6869
def client
6970
http = HTTP
7071
.headers(headers)
71-
.follow(max_hops: 4, on_redirect: @on_redirect)
72+
.follow(max_hops: 4, on_redirect: on_redirect)
7273
.timeout(connect: 5, write: 5, read: 30)
7374
.encoding(Encoding::BINARY)
7475

@@ -93,6 +94,12 @@ def basic_auth
9394
end
9495
end
9596

97+
def on_redirect
98+
proc do |from, to|
99+
@redirects.push Redirect.new(status: from.status.code, from: from.uri.to_s, to: to.uri.to_s)
100+
end
101+
end
102+
96103
def request
97104
response = client.get(@parsed_url.url, ssl_context: ssl_context)
98105
response_error!(response) unless success?(response)

lib/feedkit/response.rb

+12-3
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44

55
module Feedkit
66
class Response
7-
attr_reader :path
7+
attr_reader :path, :redirects
88

9-
def initialize(tempfile:, response:, parsed_url:)
9+
def initialize(tempfile:, response:, parsed_url:, redirects:)
1010
@tempfile = tempfile
1111
@path = tempfile.path
1212
@response = response
1313
@parsed_url = parsed_url
14+
@redirects = redirects
1415
end
1516

1617
def body
@@ -50,7 +51,7 @@ def headers
5051
end
5152

5253
def url
53-
result = @response.uri.to_s
54+
result = request_url
5455
if @parsed_url.username && @parsed_url.password
5556
parts = result.split("/")
5657
parts[2] = credentials.to_s + parts[2]
@@ -59,6 +60,14 @@ def url
5960
result
6061
end
6162

63+
def request_url
64+
if !@redirects.empty? && @redirects.all?(&:permanent?)
65+
@redirects.last.to
66+
else
67+
@parsed_url.url.to_s
68+
end
69+
end
70+
6271
def credentials
6372
username = URI.encode_www_form_component(@parsed_url.username)
6473
password = URI.encode_www_form_component(@parsed_url.password)

test/feedkit/request_test.rb

+18-5
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,25 @@ def test_should_follow_redirects
125125
stub_request(:get, first_url).to_return(response)
126126
stub_request(:get, last_url)
127127

128-
on_redirect = proc do |_, to|
129-
@location = to.uri.to_s
130-
end
128+
response = ::Feedkit::Request.download(first_url)
129+
assert_equal last_url, response.url
130+
end
131+
132+
def test_should_not_follow_temporary_redirects
133+
first_url = "http://www.example.com"
134+
last_url = "#{first_url}/final"
135+
136+
response = {
137+
status: 302,
138+
headers: {
139+
"Location" => last_url
140+
}
141+
}
142+
stub_request(:get, first_url).to_return(response)
143+
stub_request(:get, last_url)
131144

132-
response = ::Feedkit::Request.download(first_url, on_redirect: on_redirect)
133-
assert_equal last_url, @location
145+
response = ::Feedkit::Request.download(first_url)
146+
assert_equal first_url, response.url
134147
end
135148

136149
def test_should_get_caching_headers

0 commit comments

Comments
 (0)