right_http_connection 1.2.4 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +3 -0
- data/Manifest.txt +1 -0
- data/Rakefile +40 -54
- data/lib/right_http_connection.rb +103 -59
- data/lib/support.rb +109 -0
- data/lib/version.rb +32 -0
- data/right_http_connection.gemspec +63 -0
- data/spec/bad.ca +2794 -0
- data/spec/ca/Rakefile +64 -0
- data/spec/ca/ca.crt +23 -0
- data/spec/ca/ca.key +18 -0
- data/spec/ca/demoCA/index.txt +1 -0
- data/spec/ca/demoCA/serial +1 -0
- data/spec/ca/passphrase.txt +1 -0
- data/spec/ca/server.csr +12 -0
- data/spec/good.ca +23 -0
- data/spec/proxy_server.rb +75 -0
- data/spec/really_dumb_webserver.rb +113 -0
- data/spec/server.crt +62 -0
- data/spec/server.key +15 -0
- metadata +133 -14
- data/setup.rb +0 -1585
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
data/Rakefile
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler::GemHelper.install_tasks
|
2
4
|
require 'rake'
|
3
5
|
require 'rake/clean'
|
4
6
|
require 'rake/testtask'
|
@@ -6,67 +8,25 @@ require 'rake/packagetask'
|
|
6
8
|
require 'rake/gempackagetask'
|
7
9
|
require 'rake/rdoctask'
|
8
10
|
require 'rake/contrib/rubyforgepublisher'
|
11
|
+
require 'rspec/core/rake_task'
|
12
|
+
require 'cucumber/rake/task'
|
9
13
|
require 'fileutils'
|
10
|
-
require 'hoe'
|
11
14
|
include FileUtils
|
12
15
|
require File.join(File.dirname(__FILE__), 'lib', 'right_http_connection')
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
GEM_NAME = 'right_http_connection' # what ppl will type to install your gem
|
18
|
-
RUBYFORGE_PROJECT = 'rightscale' # The unix name for your project
|
19
|
-
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
20
|
-
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
21
|
-
|
22
|
-
NAME = "right_http_connection"
|
23
|
-
REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
|
24
|
-
VERS = RightHttpConnection::VERSION::STRING + (REV ? ".#{REV}" : "")
|
25
|
-
CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
|
26
|
-
RDOC_OPTS = ['--quiet', '--title', 'right_http_connection documentation',
|
27
|
-
"--opname", "index.html",
|
28
|
-
"--line-numbers",
|
29
|
-
"--main", "README",
|
30
|
-
"--inline-source"]
|
31
|
-
|
32
|
-
# Suppress Hoe's self-inclusion as a dependency for our Gem. This also keeps
|
33
|
-
# Rake & rubyforge out of the dependency list. Users must manually install
|
34
|
-
# these gems to run tests, etc.
|
35
|
-
# TRB 2/19/09: also do this for the extra_dev_deps array present in newer hoes.
|
36
|
-
# Older versions of RubyGems will try to install developer-dependencies as
|
37
|
-
# required runtime dependencies....
|
38
|
-
class Hoe
|
39
|
-
def extra_deps
|
40
|
-
@extra_deps.reject do |x|
|
41
|
-
Array(x).first == 'hoe'
|
42
|
-
end
|
43
|
-
end
|
44
|
-
def extra_dev_deps
|
45
|
-
@extra_dev_deps.reject do |x|
|
46
|
-
Array(x).first == 'hoe'
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
17
|
+
Bundler::GemHelper.install_tasks
|
18
|
+
|
19
|
+
# == Gem == #
|
50
20
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
p.description = DESCRIPTION
|
56
|
-
p.email = EMAIL
|
57
|
-
p.summary = DESCRIPTION
|
58
|
-
p.url = HOMEPATH
|
59
|
-
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
60
|
-
p.test_globs = ["test/**/test_*.rb"]
|
61
|
-
p.clean_globs = CLEAN #An array of file patterns to delete on clean.
|
62
|
-
p.remote_rdoc_dir = "right_http_gem_doc"
|
63
|
-
|
64
|
-
# == Optional
|
65
|
-
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
66
|
-
#p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
67
|
-
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
21
|
+
gemtask = Rake::GemPackageTask.new(Gem::Specification.load("right_http_connection.gemspec")) do |package|
|
22
|
+
package.package_dir = ENV['PACKAGE_DIR'] || 'pkg'
|
23
|
+
package.need_zip = true
|
24
|
+
package.need_tar = true
|
68
25
|
end
|
69
26
|
|
27
|
+
directory gemtask.package_dir
|
28
|
+
|
29
|
+
CLEAN.include(gemtask.package_dir)
|
70
30
|
|
71
31
|
desc 'Generate website files'
|
72
32
|
task :website_generate do
|
@@ -101,3 +61,29 @@ task :check_version do
|
|
101
61
|
exit
|
102
62
|
end
|
103
63
|
end
|
64
|
+
|
65
|
+
task :default => 'spec'
|
66
|
+
|
67
|
+
# == Unit Tests == #
|
68
|
+
|
69
|
+
desc "Run unit tests"
|
70
|
+
RSpec::Core::RakeTask.new
|
71
|
+
|
72
|
+
namespace :spec do
|
73
|
+
desc "Run unit tests with RCov"
|
74
|
+
RSpec::Core::RakeTask.new(:rcov) do |t|
|
75
|
+
t.rcov = true
|
76
|
+
t.rcov_opts = %q[--exclude "spec"]
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Print Specdoc for unit tests"
|
80
|
+
RSpec::Core::RakeTask.new(:doc) do |t|
|
81
|
+
t.rspec_opts = ["--format", "documentation"]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# == Functional tests == #
|
86
|
+
desc "Run functional tests"
|
87
|
+
Cucumber::Rake::Task.new do |t|
|
88
|
+
t.cucumber_opts = %w{--color --format pretty}
|
89
|
+
end
|
@@ -27,20 +27,10 @@ require "time"
|
|
27
27
|
require "logger"
|
28
28
|
|
29
29
|
$:.unshift(File.dirname(__FILE__))
|
30
|
+
require 'version'
|
31
|
+
require 'support'
|
30
32
|
require "net_fix"
|
31
33
|
|
32
|
-
|
33
|
-
module RightHttpConnection #:nodoc:
|
34
|
-
module VERSION #:nodoc:
|
35
|
-
MAJOR = 1
|
36
|
-
MINOR = 2
|
37
|
-
TINY = 4
|
38
|
-
|
39
|
-
STRING = [MAJOR, MINOR, TINY].join('.')
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
34
|
module Rightscale
|
45
35
|
|
46
36
|
=begin rdoc
|
@@ -78,13 +68,13 @@ them.
|
|
78
68
|
class HttpConnection
|
79
69
|
|
80
70
|
# Number of times to retry the request after encountering the first error
|
81
|
-
HTTP_CONNECTION_RETRY_COUNT = 3
|
71
|
+
HTTP_CONNECTION_RETRY_COUNT = 3 unless defined?(HTTP_CONNECTION_RETRY_COUNT)
|
82
72
|
# Throw a Timeout::Error if a connection isn't established within this number of seconds
|
83
|
-
HTTP_CONNECTION_OPEN_TIMEOUT = 5
|
73
|
+
HTTP_CONNECTION_OPEN_TIMEOUT = 5 unless defined?(HTTP_CONNECTION_OPEN_TIMEOUT)
|
84
74
|
# Throw a Timeout::Error if no data have been read on this connnection within this number of seconds
|
85
|
-
HTTP_CONNECTION_READ_TIMEOUT = 120
|
75
|
+
HTTP_CONNECTION_READ_TIMEOUT = 120 unless defined?(HTTP_CONNECTION_READ_TIMEOUT)
|
86
76
|
# Length of the post-error probationary period during which all requests will fail
|
87
|
-
HTTP_CONNECTION_RETRY_DELAY = 15
|
77
|
+
HTTP_CONNECTION_RETRY_DELAY = 15 unless defined?(HTTP_CONNECTION_RETRY_DELAY)
|
88
78
|
|
89
79
|
#--------------------
|
90
80
|
# class methods
|
@@ -100,13 +90,19 @@ them.
|
|
100
90
|
#
|
101
91
|
# :user_agent => 'www.HostName.com' # String to report as HTTP User agent
|
102
92
|
# :ca_file => 'path_to_file' # Path to a CA certification file in PEM format. The file can contain several CA certificates. If this parameter isn't set, HTTPS certs won't be verified.
|
93
|
+
# :fail_if_ca_mismatch => Boolean # If ca_file is set and the server certificate doesn't verify, a log line is generated regardless, but normally right_http_connection continues on past the failure. If this is set, fail to connect in that case. Defaults to false.
|
103
94
|
# :logger => Logger object # If omitted, HttpConnection logs to STDOUT
|
104
95
|
# :exception => Exception to raise # The type of exception to raise
|
105
96
|
# # if a request repeatedly fails. RuntimeError is raised if this parameter is omitted.
|
97
|
+
# :proxy_host => 'hostname' # hostname of HTTP proxy host to use, default none.
|
98
|
+
# :proxy_port => port # port of HTTP proxy host to use, default none.
|
99
|
+
# :proxy_username => 'username' # username to use for proxy authentication, default none.
|
100
|
+
# :proxy_password => 'password' # password to use for proxy authentication, default none.
|
106
101
|
# :http_connection_retry_count # by default == Rightscale::HttpConnection::HTTP_CONNECTION_RETRY_COUNT
|
107
102
|
# :http_connection_open_timeout # by default == Rightscale::HttpConnection::HTTP_CONNECTION_OPEN_TIMEOUT
|
108
103
|
# :http_connection_read_timeout # by default == Rightscale::HttpConnection::HTTP_CONNECTION_READ_TIMEOUT
|
109
104
|
# :http_connection_retry_delay # by default == Rightscale::HttpConnection::HTTP_CONNECTION_RETRY_DELAY
|
105
|
+
# :raise_on_timeout # do not perform a retry if timeout is received (false by default)
|
110
106
|
def self.params
|
111
107
|
@@params
|
112
108
|
end
|
@@ -127,28 +123,42 @@ them.
|
|
127
123
|
# Params hash:
|
128
124
|
# :user_agent => 'www.HostName.com' # String to report as HTTP User agent
|
129
125
|
# :ca_file => 'path_to_file' # A path of a CA certification file in PEM format. The file can contain several CA certificates.
|
126
|
+
# :fail_if_ca_mismatch => Boolean # If ca_file is set and the server certificate doesn't verify, a log line is generated regardless, but normally right_http_connection continues on past the failure. If this is set, fail to connect in that case. Defaults to false.
|
130
127
|
# :logger => Logger object # If omitted, HttpConnection logs to STDOUT
|
131
128
|
# :exception => Exception to raise # The type of exception to raise if a request repeatedly fails. RuntimeError is raised if this parameter is omitted.
|
129
|
+
# :proxy_host => 'hostname' # hostname of HTTP proxy host to use, default none.
|
130
|
+
# :proxy_port => port # port of HTTP proxy host to use, default none.
|
131
|
+
# :proxy_username => 'username' # username to use for proxy authentication, default none.
|
132
|
+
# :proxy_password => 'password' # password to use for proxy authentication, default none.
|
132
133
|
# :http_connection_retry_count # by default == Rightscale::HttpConnection.params[:http_connection_retry_count]
|
133
134
|
# :http_connection_open_timeout # by default == Rightscale::HttpConnection.params[:http_connection_open_timeout]
|
134
135
|
# :http_connection_read_timeout # by default == Rightscale::HttpConnection.params[:http_connection_read_timeout]
|
135
136
|
# :http_connection_retry_delay # by default == Rightscale::HttpConnection.params[:http_connection_retry_delay]
|
136
|
-
#
|
137
|
+
# :raise_on_timeout # do not perform a retry if timeout is received (false by default)
|
137
138
|
def initialize(params={})
|
138
139
|
@params = params
|
139
140
|
@params[:http_connection_retry_count] ||= @@params[:http_connection_retry_count]
|
140
141
|
@params[:http_connection_open_timeout] ||= @@params[:http_connection_open_timeout]
|
141
142
|
@params[:http_connection_read_timeout] ||= @@params[:http_connection_read_timeout]
|
142
143
|
@params[:http_connection_retry_delay] ||= @@params[:http_connection_retry_delay]
|
144
|
+
@params[:proxy_host] ||= @@params[:proxy_host]
|
145
|
+
@params[:proxy_port] ||= @@params[:proxy_port]
|
146
|
+
@params[:proxy_username] ||= @@params[:proxy_username]
|
147
|
+
@params[:proxy_password] ||= @@params[:proxy_password]
|
143
148
|
@http = nil
|
144
149
|
@server = nil
|
145
150
|
@logger = get_param(:logger) ||
|
146
151
|
(RAILS_DEFAULT_LOGGER if defined?(RAILS_DEFAULT_LOGGER)) ||
|
147
152
|
Logger.new(STDOUT)
|
153
|
+
#--------------
|
154
|
+
# Retry state - Keep track of errors on a per-server basis
|
155
|
+
#--------------
|
156
|
+
@state = {} # retry state indexed by server: consecutive error count, error time, and error
|
157
|
+
@eof = {}
|
148
158
|
end
|
149
159
|
|
150
|
-
def get_param(name)
|
151
|
-
@params[name] || @@params[name]
|
160
|
+
def get_param(name, custom_options={})
|
161
|
+
custom_options [name] || @params[name] || @@params[name]
|
152
162
|
end
|
153
163
|
|
154
164
|
# Query for the maximum size (in bytes) of a single read from the underlying
|
@@ -180,35 +190,30 @@ them.
|
|
180
190
|
end
|
181
191
|
|
182
192
|
private
|
183
|
-
#--------------
|
184
|
-
# Retry state - Keep track of errors on a per-server basis
|
185
|
-
#--------------
|
186
|
-
@@state = {} # retry state indexed by server: consecutive error count, error time, and error
|
187
|
-
@@eof = {}
|
188
193
|
|
189
194
|
# number of consecutive errors seen for server, 0 all is ok
|
190
195
|
def error_count
|
191
|
-
|
196
|
+
@state[@server] ? @state[@server][:count] : 0
|
192
197
|
end
|
193
198
|
|
194
199
|
# time of last error for server, nil if all is ok
|
195
200
|
def error_time
|
196
|
-
|
201
|
+
@state[@server] && @state[@server][:time]
|
197
202
|
end
|
198
203
|
|
199
204
|
# message for last error for server, "" if all is ok
|
200
205
|
def error_message
|
201
|
-
|
206
|
+
@state[@server] ? @state[@server][:message] : ""
|
202
207
|
end
|
203
208
|
|
204
209
|
# add an error for a server
|
205
210
|
def error_add(message)
|
206
|
-
|
211
|
+
@state[@server] = { :count => error_count+1, :time => Time.now, :message => message }
|
207
212
|
end
|
208
213
|
|
209
214
|
# reset the error state for a server (i.e. a request succeeded)
|
210
215
|
def error_reset
|
211
|
-
|
216
|
+
@state.delete(@server)
|
212
217
|
end
|
213
218
|
|
214
219
|
# Error message stuff...
|
@@ -224,25 +229,25 @@ them.
|
|
224
229
|
# Returns the number of seconds to wait before new conection retry:
|
225
230
|
# 0.5, 1, 2, 4, 8
|
226
231
|
def add_eof
|
227
|
-
(
|
228
|
-
0.25 * 2 **
|
232
|
+
(@eof[@server] ||= []).unshift Time.now
|
233
|
+
0.25 * 2 ** @eof[@server].size
|
229
234
|
end
|
230
235
|
|
231
236
|
# Returns first EOF timestamp or nul if have no EOFs being tracked.
|
232
237
|
def eof_time
|
233
|
-
|
238
|
+
@eof[@server] && @eof[@server].last
|
234
239
|
end
|
235
240
|
|
236
241
|
# Returns true if we are receiving EOFs during last @params[:http_connection_retry_delay] seconds
|
237
242
|
# and there were no successful response from server
|
238
243
|
def raise_on_eof_exception?
|
239
|
-
|
244
|
+
@eof[@server].nil? ? false : ( (Time.now.to_i-@params[:http_connection_retry_delay]) > @eof[@server].last.to_i )
|
240
245
|
end
|
241
246
|
|
242
247
|
# Reset a list of EOFs for this server.
|
243
248
|
# This is being called when we have got an successful response from server.
|
244
249
|
def eof_reset
|
245
|
-
|
250
|
+
@eof.delete(@server)
|
246
251
|
end
|
247
252
|
|
248
253
|
# Detects if an object is 'streamable' - can we read from it, and can we know the size?
|
@@ -281,14 +286,22 @@ them.
|
|
281
286
|
# close the previous if exists
|
282
287
|
finish
|
283
288
|
# create new connection
|
284
|
-
@server
|
285
|
-
@port
|
286
|
-
@protocol
|
289
|
+
@server = request_params[:server]
|
290
|
+
@port = request_params[:port]
|
291
|
+
@protocol = request_params[:protocol]
|
292
|
+
@proxy_host = request_params[:proxy_host]
|
293
|
+
@proxy_port = request_params[:proxy_port]
|
294
|
+
@proxy_username = request_params[:proxy_username]
|
295
|
+
@proxy_password = request_params[:proxy_password]
|
287
296
|
|
288
297
|
@logger.info("Opening new #{@protocol.upcase} connection to #@server:#@port")
|
289
|
-
@
|
290
|
-
|
291
|
-
|
298
|
+
@logger.info("Connecting to proxy #{@proxy_host}:#{@proxy_port} with username" +
|
299
|
+
" #{@proxy_username}") unless @proxy_host.nil?
|
300
|
+
|
301
|
+
@http = Net::HTTP.new(@server, @port, @proxy_host, @proxy_port, @proxy_username,
|
302
|
+
@proxy_password)
|
303
|
+
@http.open_timeout = get_param(:http_connection_open_timeout, request_params)
|
304
|
+
@http.read_timeout = get_param(:http_connection_read_timeout, request_params)
|
292
305
|
|
293
306
|
if @protocol == 'https'
|
294
307
|
verifyCallbackProc = Proc.new{ |ok, x509_store_ctx|
|
@@ -296,7 +309,11 @@ them.
|
|
296
309
|
msg = x509_store_ctx.error_string
|
297
310
|
#debugger
|
298
311
|
@logger.warn("##### #{@server} certificate verify failed: #{msg}") unless code == 0
|
299
|
-
|
312
|
+
if request_params[:fail_if_ca_mismatch] && code != 0
|
313
|
+
false
|
314
|
+
else
|
315
|
+
true
|
316
|
+
end
|
300
317
|
}
|
301
318
|
@http.use_ssl = true
|
302
319
|
ca_file = get_param(:ca_file)
|
@@ -304,6 +321,8 @@ them.
|
|
304
321
|
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
305
322
|
@http.verify_callback = verifyCallbackProc
|
306
323
|
@http.ca_file = ca_file
|
324
|
+
else
|
325
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
307
326
|
end
|
308
327
|
end
|
309
328
|
# open connection
|
@@ -320,45 +339,64 @@ them.
|
|
320
339
|
:port => '80' # Port of HTTP server
|
321
340
|
:protocol => 'https' # http and https are supported on any port
|
322
341
|
:request => 'requeststring' # Fully-formed HTTP request to make
|
342
|
+
:proxy_host => 'hostname' # hostname of HTTP proxy host to use, default none.
|
343
|
+
:proxy_port => port # port of HTTP proxy host to use, default none.
|
344
|
+
:proxy_username => 'username' # username to use for proxy authentication, default none.
|
345
|
+
:proxy_password => 'password' # password to use for proxy authentication, default none.
|
346
|
+
|
347
|
+
:raise_on_timeout # do not perform a retry if timeout is received (false by default)
|
348
|
+
:http_connection_retry_count
|
349
|
+
:http_connection_open_timeout
|
350
|
+
:http_connection_read_timeout
|
351
|
+
:http_connection_retry_delay
|
352
|
+
:user_agent
|
353
|
+
:exception
|
323
354
|
|
324
355
|
Raises RuntimeError, Interrupt, and params[:exception] (if specified in new).
|
325
356
|
|
326
357
|
=end
|
327
358
|
def request(request_params, &block)
|
359
|
+
current_params = @params.merge(request_params)
|
360
|
+
exception = get_param(:exception, current_params) || RuntimeError
|
361
|
+
|
328
362
|
# We save the offset here so that if we need to retry, we can return the file pointer to its initial position
|
329
|
-
mypos = get_fileptr_offset(
|
363
|
+
mypos = get_fileptr_offset(current_params)
|
330
364
|
loop do
|
365
|
+
current_params[:protocol] ||= (current_params[:port] == 443 ? 'https' : 'http')
|
366
|
+
# (re)open connection to server if none exists or params has changed
|
367
|
+
same_server_as_before = @server == current_params[:server] &&
|
368
|
+
@port == current_params[:port] &&
|
369
|
+
@protocol == current_params[:protocol]
|
370
|
+
|
331
371
|
# if we are inside a delay between retries: no requests this time!
|
332
|
-
if
|
333
|
-
|
372
|
+
# (skip this step if the endpoint has changed)
|
373
|
+
if error_count > current_params[:http_connection_retry_count] &&
|
374
|
+
error_time + current_params[:http_connection_retry_delay] > Time.now &&
|
375
|
+
same_server_as_before
|
376
|
+
|
334
377
|
# store the message (otherwise it will be lost after error_reset and
|
335
378
|
# we will raise an exception with an empty text)
|
336
379
|
banana_message_text = banana_message
|
337
380
|
@logger.warn("#{err_header} re-raising same error: #{banana_message_text} " +
|
338
381
|
"-- error count: #{error_count}, error age: #{Time.now.to_i - error_time.to_i}")
|
339
|
-
exception = get_param(:exception) || RuntimeError
|
340
382
|
raise exception.new(banana_message_text)
|
341
383
|
end
|
342
384
|
|
343
385
|
# try to connect server(if connection does not exist) and get response data
|
344
386
|
begin
|
345
|
-
|
346
|
-
|
347
|
-
request = request_params[:request]
|
348
|
-
request['User-Agent'] = get_param(:user_agent) || ''
|
349
|
-
|
350
|
-
# (re)open connection to server if none exists or params has changed
|
387
|
+
request = current_params[:request]
|
388
|
+
request['User-Agent'] = get_param(:user_agent, current_params) || ''
|
351
389
|
unless @http &&
|
352
390
|
@http.started? &&
|
353
|
-
|
354
|
-
|
355
|
-
@protocol == request_params[:protocol]
|
356
|
-
start(request_params)
|
391
|
+
same_server_as_before
|
392
|
+
start(current_params)
|
357
393
|
end
|
358
394
|
|
359
395
|
# Detect if the body is a streamable object like a file or socket. If so, stream that
|
360
396
|
# bad boy.
|
361
397
|
setup_streaming(request)
|
398
|
+
# update READ_TIMEOUT value (it can be passed with request_params hash)
|
399
|
+
@http.read_timeout = get_param(:http_connection_read_timeout, current_params)
|
362
400
|
response = @http.request(request, &block)
|
363
401
|
|
364
402
|
error_reset
|
@@ -381,7 +419,6 @@ them.
|
|
381
419
|
|
382
420
|
# if we have waited long enough - raise an exception...
|
383
421
|
if raise_on_eof_exception?
|
384
|
-
exception = get_param(:exception) || RuntimeError
|
385
422
|
@logger.warn("#{err_header} raising #{exception} due to permanent EOF being received from #{@server}, error age: #{Time.now.to_i - eof_time.to_i}")
|
386
423
|
raise exception.new("Permanent EOF is being received from #{@server}.")
|
387
424
|
else
|
@@ -392,13 +429,20 @@ them.
|
|
392
429
|
end
|
393
430
|
rescue Exception => e # See comment at bottom for the list of errors seen...
|
394
431
|
@http = nil
|
432
|
+
timeout_exception = e.is_a?(Errno::ETIMEDOUT) || e.is_a?(Timeout::Error)
|
433
|
+
# Omit retries if it was explicitly requested
|
434
|
+
if current_params[:raise_on_timeout] && timeout_exception
|
435
|
+
# #6481:
|
436
|
+
# ... When creating a resource in EC2 (instance, volume, snapshot, etc) it is undetermined what happened if the call times out.
|
437
|
+
# The resource may or may not have been created in EC2. Retrying the call may cause multiple resources to be created...
|
438
|
+
raise e
|
439
|
+
end
|
395
440
|
# if ctrl+c is pressed - we have to reraise exception to terminate proggy
|
396
|
-
if e.is_a?(Interrupt) && !
|
441
|
+
if e.is_a?(Interrupt) && !timeout_exception
|
397
442
|
@logger.debug( "#{err_header} request to server #{@server} interrupted by ctrl-c")
|
398
443
|
raise
|
399
444
|
elsif e.is_a?(ArgumentError) && e.message.include?('wrong number of arguments (5 for 4)')
|
400
445
|
# seems our net_fix patch was overriden...
|
401
|
-
exception = get_param(:exception) || RuntimeError
|
402
446
|
raise exception.new('incompatible Net::HTTP monkey-patch')
|
403
447
|
end
|
404
448
|
# oops - we got a banana: log it
|
@@ -414,7 +458,7 @@ them.
|
|
414
458
|
|
415
459
|
def finish(reason = '')
|
416
460
|
if @http && @http.started?
|
417
|
-
reason = ", reason: '#{reason}'" unless reason.
|
461
|
+
reason = ", reason: '#{reason}'" unless reason.empty?
|
418
462
|
@logger.info("Closing #{@http.use_ssl? ? 'HTTPS' : 'HTTP'} connection to #{@http.address}:#{@http.port}#{reason}")
|
419
463
|
@http.finish
|
420
464
|
end
|