rest-man 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/multi-matrix-test.yml +35 -0
- data/.github/workflows/single-matrix-test.yml +27 -0
- data/.gitignore +13 -0
- data/.mailmap +10 -0
- data/.rspec +2 -0
- data/.rubocop +2 -0
- data/.rubocop-disables.yml +386 -0
- data/.rubocop.yml +8 -0
- data/AUTHORS +106 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +843 -0
- data/Rakefile +140 -0
- data/exe/restman +92 -0
- data/lib/rest-man.rb +2 -0
- data/lib/rest_man.rb +2 -0
- data/lib/restman/abstract_response.rb +252 -0
- data/lib/restman/exceptions.rb +238 -0
- data/lib/restman/params_array.rb +72 -0
- data/lib/restman/payload.rb +234 -0
- data/lib/restman/platform.rb +49 -0
- data/lib/restman/raw_response.rb +49 -0
- data/lib/restman/request.rb +859 -0
- data/lib/restman/resource.rb +178 -0
- data/lib/restman/response.rb +90 -0
- data/lib/restman/utils.rb +274 -0
- data/lib/restman/version.rb +8 -0
- data/lib/restman/windows/root_certs.rb +105 -0
- data/lib/restman/windows.rb +8 -0
- data/lib/restman.rb +183 -0
- data/matrixeval.yml +73 -0
- data/rest-man.gemspec +41 -0
- data/spec/ISS.jpg +0 -0
- data/spec/cassettes/request_httpbin_with_basic_auth.yml +83 -0
- data/spec/cassettes/request_httpbin_with_cookies.yml +49 -0
- data/spec/cassettes/request_httpbin_with_cookies_2.yml +94 -0
- data/spec/cassettes/request_httpbin_with_cookies_3.yml +49 -0
- data/spec/cassettes/request_httpbin_with_encoding_deflate.yml +45 -0
- data/spec/cassettes/request_httpbin_with_encoding_deflate_and_accept_headers.yml +44 -0
- data/spec/cassettes/request_httpbin_with_encoding_gzip.yml +45 -0
- data/spec/cassettes/request_httpbin_with_encoding_gzip_and_accept_headers.yml +44 -0
- data/spec/cassettes/request_httpbin_with_user_agent.yml +44 -0
- data/spec/cassettes/request_mozilla_org.yml +151 -0
- data/spec/cassettes/request_mozilla_org_callback_returns_true.yml +178 -0
- data/spec/cassettes/request_mozilla_org_with_system_cert.yml +152 -0
- data/spec/cassettes/request_mozilla_org_with_system_cert_and_callback.yml +151 -0
- data/spec/helpers.rb +54 -0
- data/spec/integration/_lib.rb +1 -0
- data/spec/integration/capath_digicert/README +8 -0
- data/spec/integration/capath_digicert/ce5e74ef.0 +1 -0
- data/spec/integration/capath_digicert/digicert.crt +20 -0
- data/spec/integration/capath_digicert/update +1 -0
- data/spec/integration/capath_verisign/415660c1.0 +14 -0
- data/spec/integration/capath_verisign/7651b327.0 +14 -0
- data/spec/integration/capath_verisign/README +8 -0
- data/spec/integration/capath_verisign/verisign.crt +14 -0
- data/spec/integration/certs/digicert.crt +20 -0
- data/spec/integration/certs/verisign.crt +14 -0
- data/spec/integration/httpbin_spec.rb +137 -0
- data/spec/integration/integration_spec.rb +118 -0
- data/spec/integration/request_spec.rb +134 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/unit/_lib.rb +1 -0
- data/spec/unit/abstract_response_spec.rb +145 -0
- data/spec/unit/exceptions_spec.rb +108 -0
- data/spec/unit/params_array_spec.rb +36 -0
- data/spec/unit/payload_spec.rb +295 -0
- data/spec/unit/raw_response_spec.rb +22 -0
- data/spec/unit/request2_spec.rb +54 -0
- data/spec/unit/request_spec.rb +1205 -0
- data/spec/unit/resource_spec.rb +134 -0
- data/spec/unit/response_spec.rb +252 -0
- data/spec/unit/restclient_spec.rb +80 -0
- data/spec/unit/utils_spec.rb +147 -0
- data/spec/unit/windows/root_certs_spec.rb +22 -0
- metadata +336 -0
data/Rakefile
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
# load `rake build/install/release tasks'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require_relative './lib/restman/version'
|
4
|
+
|
5
|
+
namespace :ruby do
|
6
|
+
Bundler::GemHelper.install_tasks(:name => 'rest-man')
|
7
|
+
end
|
8
|
+
|
9
|
+
require "rspec/core/rake_task"
|
10
|
+
|
11
|
+
desc "Run all specs"
|
12
|
+
RSpec::Core::RakeTask.new('spec')
|
13
|
+
|
14
|
+
desc "Run unit specs"
|
15
|
+
RSpec::Core::RakeTask.new('spec:unit') do |t|
|
16
|
+
t.pattern = 'spec/unit/*_spec.rb'
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run integration specs"
|
20
|
+
RSpec::Core::RakeTask.new('spec:integration') do |t|
|
21
|
+
t.pattern = 'spec/integration/*_spec.rb'
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Print specdocs"
|
25
|
+
RSpec::Core::RakeTask.new(:doc) do |t|
|
26
|
+
t.rspec_opts = ["--format", "specdoc", "--dry-run"]
|
27
|
+
t.pattern = 'spec/**/*_spec.rb'
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Run all examples with RCov"
|
31
|
+
RSpec::Core::RakeTask.new('rcov') do |t|
|
32
|
+
t.pattern = 'spec/*_spec.rb'
|
33
|
+
t.rcov = true
|
34
|
+
t.rcov_opts = ['--exclude', 'examples']
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'Regenerate authors file'
|
38
|
+
task :authors do
|
39
|
+
Dir.chdir(File.dirname(__FILE__)) do
|
40
|
+
File.open('AUTHORS', 'w') do |f|
|
41
|
+
f.write <<-EOM
|
42
|
+
The Ruby REST Client would not be what it is today without the help of
|
43
|
+
the following kind souls:
|
44
|
+
|
45
|
+
EOM
|
46
|
+
end
|
47
|
+
|
48
|
+
sh 'git shortlog -s | cut -f 2 >> AUTHORS'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
task :default do
|
53
|
+
sh 'rake -T'
|
54
|
+
end
|
55
|
+
|
56
|
+
def alias_task(alias_task, original)
|
57
|
+
desc "Alias for rake #{original}"
|
58
|
+
task alias_task, Rake.application[original].arg_names => original
|
59
|
+
end
|
60
|
+
alias_task(:test, :spec)
|
61
|
+
|
62
|
+
############################
|
63
|
+
|
64
|
+
WindowsPlatforms = %w{x86-mingw32 x64-mingw32 x86-mswin32}
|
65
|
+
|
66
|
+
namespace :all do
|
67
|
+
|
68
|
+
desc "Build rest-man #{RestMan::VERSION} for all platforms"
|
69
|
+
task :build => ['ruby:build'] + \
|
70
|
+
WindowsPlatforms.map {|p| "windows:#{p}:build"}
|
71
|
+
|
72
|
+
desc "Create tag v#{RestMan::VERSION} and for all platforms build and " \
|
73
|
+
"push rest-man #{RestMan::VERSION} to Rubygems"
|
74
|
+
task :release => ['build', 'ruby:release'] + \
|
75
|
+
WindowsPlatforms.map {|p| "windows:#{p}:push"}
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
namespace :windows do
|
80
|
+
spec_path = File.join(File.dirname(__FILE__), 'rest-man.windows.gemspec')
|
81
|
+
|
82
|
+
WindowsPlatforms.each do |platform|
|
83
|
+
namespace platform do
|
84
|
+
gem_filename = "rest-man-#{RestMan::VERSION}-#{platform}.gem"
|
85
|
+
base = File.dirname(__FILE__)
|
86
|
+
pkg_dir = File.join(base, 'pkg')
|
87
|
+
gem_file_path = File.join(pkg_dir, gem_filename)
|
88
|
+
|
89
|
+
desc "Build #{gem_filename} into the pkg directory"
|
90
|
+
task 'build' do
|
91
|
+
orig_platform = ENV['BUILD_PLATFORM']
|
92
|
+
begin
|
93
|
+
ENV['BUILD_PLATFORM'] = platform
|
94
|
+
|
95
|
+
sh("gem build -V #{spec_path}") do |ok, res|
|
96
|
+
if ok
|
97
|
+
FileUtils.mkdir_p(pkg_dir)
|
98
|
+
FileUtils.mv(File.join(base, gem_filename), pkg_dir)
|
99
|
+
Bundler.ui.confirm("rest-man #{RestMan::VERSION} " \
|
100
|
+
"built to pkg/#{gem_filename}")
|
101
|
+
else
|
102
|
+
abort "Command `gem build` failed: #{res}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
ensure
|
107
|
+
ENV['BUILD_PLATFORM'] = orig_platform
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
desc "Push #{gem_filename} to Rubygems"
|
112
|
+
task 'push' do
|
113
|
+
sh("gem push #{gem_file_path}")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
############################
|
121
|
+
|
122
|
+
require 'rdoc/task'
|
123
|
+
|
124
|
+
Rake::RDocTask.new do |t|
|
125
|
+
t.rdoc_dir = 'rdoc'
|
126
|
+
t.title = "rest-man, fetch RESTful resources effortlessly"
|
127
|
+
t.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
128
|
+
t.options << '--charset' << 'utf-8'
|
129
|
+
t.rdoc_files.include('README.md')
|
130
|
+
t.rdoc_files.include('lib/*.rb')
|
131
|
+
end
|
132
|
+
|
133
|
+
############################
|
134
|
+
|
135
|
+
require 'rubocop/rake_task'
|
136
|
+
|
137
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
138
|
+
t.options = ['--display-cop-names']
|
139
|
+
end
|
140
|
+
alias_task(:lint, :rubocop)
|
data/exe/restman
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'restman'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
def usage(why = nil)
|
10
|
+
puts "failed for reason: #{why}" if why
|
11
|
+
puts "usage: restman [get|put|post|delete] url|name [username] [password]"
|
12
|
+
puts " The verb is optional, if you leave it off you'll get an interactive shell."
|
13
|
+
puts " put and post both take the input body on stdin."
|
14
|
+
exit(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
POSSIBLE_VERBS = ['get', 'put', 'post', 'delete']
|
18
|
+
|
19
|
+
if POSSIBLE_VERBS.include? ARGV.first
|
20
|
+
@verb = ARGV.shift
|
21
|
+
else
|
22
|
+
@verb = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
@url = ARGV.shift || 'http://localhost:4567'
|
26
|
+
|
27
|
+
config = YAML.load(File.read(ENV['HOME'] + "/.restman")) rescue {}
|
28
|
+
|
29
|
+
if (c = config[@url])
|
30
|
+
@url, @username, @password = [c['url'], c['username'], c['password']]
|
31
|
+
else
|
32
|
+
@url, @username, @password = [@url, * ARGV]
|
33
|
+
end
|
34
|
+
|
35
|
+
usage("invalid url '#{@url}") unless @url =~ /^https?/
|
36
|
+
usage("too few args") unless ARGV.size < 3
|
37
|
+
|
38
|
+
def r
|
39
|
+
@r ||= RestMan::Resource.new(@url, @username, @password)
|
40
|
+
end
|
41
|
+
|
42
|
+
r # force rc to load
|
43
|
+
|
44
|
+
if @verb
|
45
|
+
begin
|
46
|
+
if %w( put post ).include? @verb
|
47
|
+
puts r.send(@verb, STDIN.read)
|
48
|
+
else
|
49
|
+
puts r.send(@verb)
|
50
|
+
end
|
51
|
+
exit 0
|
52
|
+
rescue RestMan::Exception => e
|
53
|
+
puts e.response.body if e.respond_to?(:response) && e.response
|
54
|
+
raise
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
POSSIBLE_VERBS.each do |m|
|
59
|
+
define_method(m.to_sym) do |path, *args, &b|
|
60
|
+
r[path].public_send(m.to_sym, *args, &b)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def method_missing(s, * args, & b)
|
65
|
+
if POSSIBLE_VERBS.include? s
|
66
|
+
begin
|
67
|
+
r.send(s, *args, & b)
|
68
|
+
rescue RestMan::RequestFailed => e
|
69
|
+
print STDERR, e.response.body
|
70
|
+
raise e
|
71
|
+
end
|
72
|
+
else
|
73
|
+
super
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
require 'irb'
|
78
|
+
require 'irb/completion'
|
79
|
+
|
80
|
+
if File.exist? ".irbrc"
|
81
|
+
ENV['IRBRC'] = ".irbrc"
|
82
|
+
end
|
83
|
+
|
84
|
+
rcfile = File.expand_path("~/.restmanrc")
|
85
|
+
if File.exist?(rcfile)
|
86
|
+
load(rcfile)
|
87
|
+
end
|
88
|
+
|
89
|
+
ARGV.clear
|
90
|
+
|
91
|
+
IRB.start
|
92
|
+
exit!
|
data/lib/rest-man.rb
ADDED
data/lib/rest_man.rb
ADDED
@@ -0,0 +1,252 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'http-cookie'
|
3
|
+
|
4
|
+
module RestMan
|
5
|
+
|
6
|
+
module AbstractResponse
|
7
|
+
|
8
|
+
attr_reader :net_http_res, :request, :start_time, :end_time, :duration
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
raise NotImplementedError.new('must override in subclass')
|
12
|
+
end
|
13
|
+
|
14
|
+
# Logger from the request, potentially nil.
|
15
|
+
def log
|
16
|
+
request.log
|
17
|
+
end
|
18
|
+
|
19
|
+
def log_response
|
20
|
+
return unless log
|
21
|
+
|
22
|
+
code = net_http_res.code
|
23
|
+
res_name = net_http_res.class.to_s.gsub(/\ANet::HTTP/, '')
|
24
|
+
content_type = (net_http_res['Content-type'] || '').gsub(/;.*\z/, '')
|
25
|
+
|
26
|
+
log << "# => #{code} #{res_name} | #{content_type} #{size} bytes, #{sprintf('%.2f', duration)}s\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
# HTTP status code
|
30
|
+
def code
|
31
|
+
@code ||= @net_http_res.code.to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
def history
|
35
|
+
@history ||= request.redirection_history || []
|
36
|
+
end
|
37
|
+
|
38
|
+
# A hash of the headers, beautified with symbols and underscores.
|
39
|
+
# e.g. "Content-type" will become :content_type.
|
40
|
+
def headers
|
41
|
+
@headers ||= AbstractResponse.beautify_headers(@net_http_res.to_hash)
|
42
|
+
end
|
43
|
+
|
44
|
+
# The raw headers.
|
45
|
+
def raw_headers
|
46
|
+
@raw_headers ||= @net_http_res.to_hash
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param [Net::HTTPResponse] net_http_res
|
50
|
+
# @param [RestMan::Request] request
|
51
|
+
# @param [Time] start_time
|
52
|
+
def response_set_vars(net_http_res, request, start_time)
|
53
|
+
@net_http_res = net_http_res
|
54
|
+
@request = request
|
55
|
+
@start_time = start_time
|
56
|
+
@end_time = Time.now
|
57
|
+
|
58
|
+
if @start_time
|
59
|
+
@duration = @end_time - @start_time
|
60
|
+
else
|
61
|
+
@duration = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
# prime redirection history
|
65
|
+
history
|
66
|
+
end
|
67
|
+
|
68
|
+
# Hash of cookies extracted from response headers.
|
69
|
+
#
|
70
|
+
# NB: This will return only cookies whose domain matches this request, and
|
71
|
+
# may not even return all of those cookies if there are duplicate names.
|
72
|
+
# Use the full cookie_jar for more nuanced access.
|
73
|
+
#
|
74
|
+
# @see #cookie_jar
|
75
|
+
#
|
76
|
+
# @return [Hash]
|
77
|
+
#
|
78
|
+
def cookies
|
79
|
+
hash = {}
|
80
|
+
|
81
|
+
cookie_jar.cookies(@request.uri).each do |cookie|
|
82
|
+
hash[cookie.name] = cookie.value
|
83
|
+
end
|
84
|
+
|
85
|
+
hash
|
86
|
+
end
|
87
|
+
|
88
|
+
# Cookie jar extracted from response headers.
|
89
|
+
#
|
90
|
+
# @return [HTTP::CookieJar]
|
91
|
+
#
|
92
|
+
def cookie_jar
|
93
|
+
return @cookie_jar if defined?(@cookie_jar) && @cookie_jar
|
94
|
+
|
95
|
+
jar = @request.cookie_jar.dup
|
96
|
+
headers.fetch(:set_cookie, []).each do |cookie|
|
97
|
+
jar.parse(cookie, @request.uri)
|
98
|
+
end
|
99
|
+
|
100
|
+
@cookie_jar = jar
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return the default behavior corresponding to the response code:
|
104
|
+
#
|
105
|
+
# For 20x status codes: return the response itself
|
106
|
+
#
|
107
|
+
# For 30x status codes:
|
108
|
+
# 301, 302, 307: redirect GET / HEAD if there is a Location header
|
109
|
+
# 303: redirect, changing method to GET, if there is a Location header
|
110
|
+
#
|
111
|
+
# For all other responses, raise a response exception
|
112
|
+
#
|
113
|
+
def return!(&block)
|
114
|
+
case code
|
115
|
+
when 200..207
|
116
|
+
self
|
117
|
+
when 301, 302, 307
|
118
|
+
case request.method
|
119
|
+
when 'get', 'head'
|
120
|
+
check_max_redirects
|
121
|
+
follow_redirection(&block)
|
122
|
+
else
|
123
|
+
raise exception_with_response
|
124
|
+
end
|
125
|
+
when 303
|
126
|
+
check_max_redirects
|
127
|
+
follow_get_redirection(&block)
|
128
|
+
else
|
129
|
+
raise exception_with_response
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_i
|
134
|
+
warn('warning: calling Response#to_i is not recommended')
|
135
|
+
super
|
136
|
+
end
|
137
|
+
|
138
|
+
def description
|
139
|
+
"#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n"
|
140
|
+
end
|
141
|
+
|
142
|
+
# Follow a redirection response by making a new HTTP request to the
|
143
|
+
# redirection target.
|
144
|
+
def follow_redirection(&block)
|
145
|
+
_follow_redirection(request.args.dup, &block)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Follow a redirection response, but change the HTTP method to GET and drop
|
149
|
+
# the payload from the original request.
|
150
|
+
def follow_get_redirection(&block)
|
151
|
+
new_args = request.args.dup
|
152
|
+
new_args[:method] = :get
|
153
|
+
new_args.delete(:payload)
|
154
|
+
|
155
|
+
_follow_redirection(new_args, &block)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Convert headers hash into canonical form.
|
159
|
+
#
|
160
|
+
# Header names will be converted to lowercase symbols with underscores
|
161
|
+
# instead of hyphens.
|
162
|
+
#
|
163
|
+
# Headers specified multiple times will be joined by comma and space,
|
164
|
+
# except for Set-Cookie, which will always be an array.
|
165
|
+
#
|
166
|
+
# Per RFC 2616, if a server sends multiple headers with the same key, they
|
167
|
+
# MUST be able to be joined into a single header by a comma. However,
|
168
|
+
# Set-Cookie (RFC 6265) cannot because commas are valid within cookie
|
169
|
+
# definitions. The newer RFC 7230 notes (3.2.2) that Set-Cookie should be
|
170
|
+
# handled as a special case.
|
171
|
+
#
|
172
|
+
# http://tools.ietf.org/html/rfc2616#section-4.2
|
173
|
+
# http://tools.ietf.org/html/rfc7230#section-3.2.2
|
174
|
+
# http://tools.ietf.org/html/rfc6265
|
175
|
+
#
|
176
|
+
# @param headers [Hash]
|
177
|
+
# @return [Hash]
|
178
|
+
#
|
179
|
+
def self.beautify_headers(headers)
|
180
|
+
headers.inject({}) do |out, (key, value)|
|
181
|
+
key_sym = key.tr('-', '_').downcase.to_sym
|
182
|
+
|
183
|
+
# Handle Set-Cookie specially since it cannot be joined by comma.
|
184
|
+
if key.downcase == 'set-cookie'
|
185
|
+
out[key_sym] = value
|
186
|
+
else
|
187
|
+
out[key_sym] = value.join(', ')
|
188
|
+
end
|
189
|
+
|
190
|
+
out
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
# Follow a redirection
|
197
|
+
#
|
198
|
+
# @param new_args [Hash] Start with this hash of arguments for the
|
199
|
+
# redirection request. The hash will be mutated, so be sure to dup any
|
200
|
+
# existing hash that should not be modified.
|
201
|
+
#
|
202
|
+
def _follow_redirection(new_args, &block)
|
203
|
+
|
204
|
+
# parse location header and merge into existing URL
|
205
|
+
url = headers[:location]
|
206
|
+
|
207
|
+
# cannot follow redirection if there is no location header
|
208
|
+
unless url
|
209
|
+
raise exception_with_response
|
210
|
+
end
|
211
|
+
|
212
|
+
# handle relative redirects
|
213
|
+
unless url.start_with?('http')
|
214
|
+
url = URI.parse(request.url).merge(url).to_s
|
215
|
+
end
|
216
|
+
new_args[:url] = url
|
217
|
+
|
218
|
+
new_args[:password] = request.password
|
219
|
+
new_args[:user] = request.user
|
220
|
+
new_args[:headers] = request.headers
|
221
|
+
new_args[:max_redirects] = request.max_redirects - 1
|
222
|
+
|
223
|
+
# pass through our new cookie jar
|
224
|
+
new_args[:cookies] = cookie_jar
|
225
|
+
|
226
|
+
# prepare new request
|
227
|
+
new_req = Request.new(new_args)
|
228
|
+
|
229
|
+
# append self to redirection history
|
230
|
+
new_req.redirection_history = history + [self]
|
231
|
+
|
232
|
+
# execute redirected request
|
233
|
+
new_req.execute(&block)
|
234
|
+
end
|
235
|
+
|
236
|
+
def check_max_redirects
|
237
|
+
if request.max_redirects <= 0
|
238
|
+
raise exception_with_response
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def exception_with_response
|
243
|
+
begin
|
244
|
+
klass = Exceptions::EXCEPTIONS_MAP.fetch(code)
|
245
|
+
rescue KeyError
|
246
|
+
raise RequestFailed.new(self, code)
|
247
|
+
end
|
248
|
+
|
249
|
+
raise klass.new(self, code)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|