added follow_insecure_redirects, which allows users to opt in on https-to-http redirects (shut down by default)

This commit is contained in:
HoneyryderChuck 2018-06-06 17:43:31 +01:00
parent c521f226fc
commit 0be7efaab2
2 changed files with 49 additions and 3 deletions

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
module HTTPX
InsecureRedirectError = Class.new(Error)
module Plugins
module FollowRedirects
module InstanceMethods
@ -48,9 +49,24 @@ module HTTPX
private
def fetch_response(request)
response = super
if response &&
REDIRECT_STATUS.include?(response.status) &&
!@options.follow_insecure_redirects
redirect_uri = __get_location_from_response(response)
if response.uri.scheme == "https" &&
redirect_uri.scheme == "http"
error = InsecureRedirectError.new(redirect_uri.to_s)
error.set_backtrace(caller)
response = ErrorResponse.new(error, 0, @options)
end
end
response
end
def __build_redirect_req(request, response, options)
redirect_uri = URI(response.headers["location"])
redirect_uri = response.uri.merge(redirect_uri) if redirect_uri.relative?
redirect_uri = __get_location_from_response(response)
# TODO: integrate cookies in the next request
# redirects are **ALWAYS** GET
@ -58,12 +74,24 @@ module HTTPX
body: request.body)
__build_req(:get, redirect_uri, retry_options)
end
def __get_location_from_response(response)
location_uri = URI(response.headers["location"])
location_uri = response.uri.merge(location_uri) if location_uri.relative?
location_uri
end
end
module OptionsMethods
def self.included(klass)
super
klass.def_option(:max_redirects)
klass.def_option(:max_redirects) do |num|
num = Integer(num)
raise Error, ":max_redirects must be positive" unless num.positive?
num
end
klass.def_option(:follow_insecure_redirects)
end
end
end

View File

@ -36,6 +36,20 @@ module Requests
verify_status(response, 302)
end
def test_plugin_follow_insecure_no_insecure_downgrade
return unless origin.start_with?("https")
client = HTTPX.plugin(:follow_redirects).max_redirects(1)
response = client.get(insecure_redirect_uri)
assert response.is_a?(HTTPX::ErrorResponse), "request should not follow insecure URLs"
insecure_client = HTTPX.plugin(:follow_redirects)
.max_redirects(1)
.with(follow_insecure_redirects: true)
insecure_response = insecure_client.get(insecure_redirect_uri)
verify_status(insecure_response, 200)
end
private
def redirect_uri
@ -46,6 +60,10 @@ module Requests
build_uri("/redirect/#{n}")
end
def insecure_redirect_uri
build_uri("/redirect-to?url=http://www.google.com")
end
def redirect_location
build_uri("/get")
end