right_http_connection 1.2.1 → 1.2.3
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.
- data/History.txt +11 -1
- data/README.txt +1 -1
- data/lib/right_http_connection.rb +88 -36
- metadata +42 -35
data/History.txt
CHANGED
@@ -39,4 +39,14 @@ Initial public release
|
|
39
39
|
* "RightAws: incompatible Net::HTTP monkey-patch" exception is raised if our net_fix
|
40
40
|
patch was overriden (by attachment_fu for example, to avoid this load attachment_fu
|
41
41
|
before loading the right_http_connection gem).
|
42
|
-
|
42
|
+
|
43
|
+
== 1.2.2
|
44
|
+
|
45
|
+
* r3524, konstantin, 2008-04-17 11:35:42 +0400
|
46
|
+
* Fixed a problem with incorrect error handling (connection retries always failed).
|
47
|
+
|
48
|
+
== 1.2.3
|
49
|
+
|
50
|
+
- Added support for setting retry & timeout parameters in the constructor
|
51
|
+
- Improve handling of data streams during upload: if there is a failure and a retry, reset
|
52
|
+
the seek pointer for the subsequent re-request
|
data/README.txt
CHANGED
@@ -34,7 +34,7 @@ module RightHttpConnection #:nodoc:
|
|
34
34
|
module VERSION #:nodoc:
|
35
35
|
MAJOR = 1
|
36
36
|
MINOR = 2
|
37
|
-
TINY =
|
37
|
+
TINY = 3
|
38
38
|
|
39
39
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
40
40
|
end
|
@@ -82,22 +82,31 @@ them.
|
|
82
82
|
# Throw a Timeout::Error if a connection isn't established within this number of seconds
|
83
83
|
HTTP_CONNECTION_OPEN_TIMEOUT = 5
|
84
84
|
# Throw a Timeout::Error if no data have been read on this connnection within this number of seconds
|
85
|
-
HTTP_CONNECTION_READ_TIMEOUT =
|
85
|
+
HTTP_CONNECTION_READ_TIMEOUT = 120
|
86
86
|
# Length of the post-error probationary period during which all requests will fail
|
87
87
|
HTTP_CONNECTION_RETRY_DELAY = 15
|
88
88
|
|
89
89
|
#--------------------
|
90
90
|
# class methods
|
91
91
|
#--------------------
|
92
|
-
|
93
|
-
# :user_agent => 'www.HostName.com' # String to report as HTTP User agent
|
94
|
-
# :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.
|
95
|
-
# :logger => Logger object # If omitted, HttpConnection logs to STDOUT
|
96
|
-
# :exception => Exception to raise # The type of exception to raise
|
97
|
-
# if a request repeatedly fails. RuntimeError is raised if this parameter is omitted.
|
92
|
+
#
|
98
93
|
@@params = {}
|
94
|
+
@@params[:http_connection_retry_count] = HTTP_CONNECTION_RETRY_COUNT
|
95
|
+
@@params[:http_connection_open_timeout] = HTTP_CONNECTION_OPEN_TIMEOUT
|
96
|
+
@@params[:http_connection_read_timeout] = HTTP_CONNECTION_READ_TIMEOUT
|
97
|
+
@@params[:http_connection_retry_delay] = HTTP_CONNECTION_RETRY_DELAY
|
99
98
|
|
100
|
-
# Query the global (class-level) parameters
|
99
|
+
# Query the global (class-level) parameters:
|
100
|
+
#
|
101
|
+
# :user_agent => 'www.HostName.com' # String to report as HTTP User agent
|
102
|
+
# :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.
|
103
|
+
# :logger => Logger object # If omitted, HttpConnection logs to STDOUT
|
104
|
+
# :exception => Exception to raise # The type of exception to raise
|
105
|
+
# # if a request repeatedly fails. RuntimeError is raised if this parameter is omitted.
|
106
|
+
# :http_connection_retry_count # by default == Rightscale::HttpConnection::HTTP_CONNECTION_RETRY_COUNT
|
107
|
+
# :http_connection_open_timeout # by default == Rightscale::HttpConnection::HTTP_CONNECTION_OPEN_TIMEOUT
|
108
|
+
# :http_connection_read_timeout # by default == Rightscale::HttpConnection::HTTP_CONNECTION_READ_TIMEOUT
|
109
|
+
# :http_connection_retry_delay # by default == Rightscale::HttpConnection::HTTP_CONNECTION_RETRY_DELAY
|
101
110
|
def self.params
|
102
111
|
@@params
|
103
112
|
end
|
@@ -115,16 +124,22 @@ them.
|
|
115
124
|
attr_accessor :params # see @@params
|
116
125
|
attr_accessor :logger
|
117
126
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
127
|
+
# Params hash:
|
128
|
+
# :user_agent => 'www.HostName.com' # String to report as HTTP User agent
|
129
|
+
# :ca_file => 'path_to_file' # A path of a CA certification file in PEM format. The file can contain several CA certificates.
|
130
|
+
# :logger => Logger object # If omitted, HttpConnection logs to STDOUT
|
131
|
+
# :exception => Exception to raise # The type of exception to raise if a request repeatedly fails. RuntimeError is raised if this parameter is omitted.
|
132
|
+
# :http_connection_retry_count # by default == Rightscale::HttpConnection.params[:http_connection_retry_count]
|
133
|
+
# :http_connection_open_timeout # by default == Rightscale::HttpConnection.params[:http_connection_open_timeout]
|
134
|
+
# :http_connection_read_timeout # by default == Rightscale::HttpConnection.params[:http_connection_read_timeout]
|
135
|
+
# :http_connection_retry_delay # by default == Rightscale::HttpConnection.params[:http_connection_retry_delay]
|
136
|
+
#
|
126
137
|
def initialize(params={})
|
127
|
-
@params = params
|
138
|
+
@params = params
|
139
|
+
@params[:http_connection_retry_count] ||= @@params[:http_connection_retry_count]
|
140
|
+
@params[:http_connection_open_timeout] ||= @@params[:http_connection_open_timeout]
|
141
|
+
@params[:http_connection_read_timeout] ||= @@params[:http_connection_read_timeout]
|
142
|
+
@params[:http_connection_retry_delay] ||= @@params[:http_connection_retry_delay]
|
128
143
|
@http = nil
|
129
144
|
@server = nil
|
130
145
|
@logger = get_param(:logger) ||
|
@@ -218,10 +233,10 @@ them.
|
|
218
233
|
@@eof[@server] && @@eof[@server].last
|
219
234
|
end
|
220
235
|
|
221
|
-
# Returns true if we are receiving EOFs during last
|
236
|
+
# Returns true if we are receiving EOFs during last @params[:http_connection_retry_delay] seconds
|
222
237
|
# and there were no successful response from server
|
223
238
|
def raise_on_eof_exception?
|
224
|
-
@@eof[@server].blank? ? false : ( (Time.now.to_i
|
239
|
+
@@eof[@server].blank? ? false : ( (Time.now.to_i-@params[:http_connection_retry_delay]) > @@eof[@server].last.to_i )
|
225
240
|
end
|
226
241
|
|
227
242
|
# Reset a list of EOFs for this server.
|
@@ -229,6 +244,36 @@ them.
|
|
229
244
|
def eof_reset
|
230
245
|
@@eof.delete(@server)
|
231
246
|
end
|
247
|
+
|
248
|
+
# Detects if an object is 'streamable' - can we read from it, and can we know the size?
|
249
|
+
def setup_streaming(request)
|
250
|
+
if(request.body && request.body.respond_to?(:read))
|
251
|
+
body = request.body
|
252
|
+
request.content_length = body.respond_to?(:lstat) ? body.lstat.size : body.size
|
253
|
+
request.body_stream = request.body
|
254
|
+
true
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def get_fileptr_offset(request_params)
|
259
|
+
request_params[:request].body.pos
|
260
|
+
rescue Exception => e
|
261
|
+
# Probably caught this because the body doesn't support the pos() method, like if it is a socket.
|
262
|
+
# Just return 0 and get on with life.
|
263
|
+
0
|
264
|
+
end
|
265
|
+
|
266
|
+
def reset_fileptr_offset(request, offset = 0)
|
267
|
+
if(request.body_stream && request.body_stream.respond_to?(:pos))
|
268
|
+
begin
|
269
|
+
request.body_stream.pos = offset
|
270
|
+
rescue Exception => e
|
271
|
+
@logger.warn("Failed file pointer reset; aborting HTTP retries." +
|
272
|
+
" -- #{err_header} #{e.inspect}")
|
273
|
+
raise e
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
232
277
|
|
233
278
|
# Start a fresh connection. The object closes any existing connection and
|
234
279
|
# opens a new one.
|
@@ -242,8 +287,8 @@ them.
|
|
242
287
|
|
243
288
|
@logger.info("Opening new #{@protocol.upcase} connection to #@server:#@port")
|
244
289
|
@http = Net::HTTP.new(@server, @port)
|
245
|
-
@http.open_timeout =
|
246
|
-
@http.read_timeout =
|
290
|
+
@http.open_timeout = @params[:http_connection_open_timeout]
|
291
|
+
@http.read_timeout = @params[:http_connection_read_timeout]
|
247
292
|
|
248
293
|
if @protocol == 'https'
|
249
294
|
verifyCallbackProc = Proc.new{ |ok, x509_store_ctx|
|
@@ -271,25 +316,30 @@ them.
|
|
271
316
|
Send HTTP request to server
|
272
317
|
|
273
318
|
request_params hash:
|
274
|
-
:server => 'www.HostName.com' Hostname or IP address of HTTP server
|
275
|
-
:port => '80' Port of HTTP server
|
276
|
-
:protocol => 'https' http and https are supported on any port
|
277
|
-
:request => 'requeststring' Fully-formed HTTP request to make
|
319
|
+
:server => 'www.HostName.com' # Hostname or IP address of HTTP server
|
320
|
+
:port => '80' # Port of HTTP server
|
321
|
+
:protocol => 'https' # http and https are supported on any port
|
322
|
+
:request => 'requeststring' # Fully-formed HTTP request to make
|
278
323
|
|
279
324
|
Raises RuntimeError, Interrupt, and params[:exception] (if specified in new).
|
280
325
|
|
281
326
|
=end
|
282
327
|
def request(request_params, &block)
|
328
|
+
# 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(request_params)
|
283
330
|
loop do
|
284
331
|
# if we are inside a delay between retries: no requests this time!
|
285
|
-
if error_count >
|
286
|
-
|
287
|
-
|
332
|
+
if error_count > @params[:http_connection_retry_count] &&
|
333
|
+
error_time + @params[:http_connection_retry_delay] > Time.now
|
334
|
+
# store the message (otherwise it will be lost after error_reset and
|
335
|
+
# we will raise an exception with an empty text)
|
336
|
+
banana_message_text = banana_message
|
337
|
+
@logger.warn("#{err_header} re-raising same error: #{banana_message_text} " +
|
288
338
|
"-- error count: #{error_count}, error age: #{Time.now.to_i - error_time.to_i}")
|
289
339
|
exception = get_param(:exception) || RuntimeError
|
290
|
-
raise exception.new(
|
340
|
+
raise exception.new(banana_message_text)
|
291
341
|
end
|
292
|
-
|
342
|
+
|
293
343
|
# try to connect server(if connection does not exist) and get response data
|
294
344
|
begin
|
295
345
|
request_params[:protocol] ||= (request_params[:port] == 443 ? 'https' : 'http')
|
@@ -308,11 +358,7 @@ them.
|
|
308
358
|
|
309
359
|
# Detect if the body is a streamable object like a file or socket. If so, stream that
|
310
360
|
# bad boy.
|
311
|
-
|
312
|
-
body = request.body
|
313
|
-
request.content_length = body.respond_to?(:lstat) ? body.lstat.size : body.size
|
314
|
-
request.body_stream = request.body
|
315
|
-
end
|
361
|
+
setup_streaming(request)
|
316
362
|
response = @http.request(request, &block)
|
317
363
|
|
318
364
|
error_reset
|
@@ -341,6 +387,8 @@ them.
|
|
341
387
|
else
|
342
388
|
# ... else just sleep a bit before new retry
|
343
389
|
sleep(add_eof)
|
390
|
+
# We will be retrying the request, so reset the file pointer
|
391
|
+
reset_fileptr_offset(request, mypos)
|
344
392
|
end
|
345
393
|
rescue Exception => e # See comment at bottom for the list of errors seen...
|
346
394
|
@http = nil
|
@@ -356,6 +404,10 @@ them.
|
|
356
404
|
# oops - we got a banana: log it
|
357
405
|
error_add(e.message)
|
358
406
|
@logger.warn("#{err_header} request failure count: #{error_count}, exception: #{e.inspect}")
|
407
|
+
|
408
|
+
# We will be retrying the request, so reset the file pointer
|
409
|
+
reset_fileptr_offset(request, mypos)
|
410
|
+
|
359
411
|
end
|
360
412
|
end
|
361
413
|
end
|
metadata
CHANGED
@@ -1,33 +1,28 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.4
|
3
|
-
specification_version: 1
|
4
2
|
name: right_http_connection
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.2.
|
7
|
-
date: 2008-02-11 00:00:00 -08:00
|
8
|
-
summary: RightScale's robust HTTP/S connection module
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: support@rightscale.com
|
12
|
-
homepage: http://rightaws.rubyforge.org
|
13
|
-
rubyforge_project: rightaws
|
14
|
-
description: RightScale's robust HTTP/S connection module
|
15
|
-
autorequire:
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
version: 1.2.3
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
7
|
- RightScale
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-06-27 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: RightScale's robust HTTP/S connection module
|
17
|
+
email: support@rightscale.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- History.txt
|
24
|
+
- Manifest.txt
|
25
|
+
- README.txt
|
31
26
|
files:
|
32
27
|
- History.txt
|
33
28
|
- Manifest.txt
|
@@ -36,20 +31,32 @@ files:
|
|
36
31
|
- lib/net_fix.rb
|
37
32
|
- lib/right_http_connection.rb
|
38
33
|
- setup.rb
|
39
|
-
|
40
|
-
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: http://rightaws.rubyforge.org
|
36
|
+
post_install_message:
|
41
37
|
rdoc_options:
|
42
38
|
- --main
|
43
39
|
- README.txt
|
44
|
-
|
45
|
-
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
52
54
|
requirements: []
|
53
55
|
|
54
|
-
|
56
|
+
rubyforge_project: rightaws
|
57
|
+
rubygems_version: 1.0.1
|
58
|
+
signing_key:
|
59
|
+
specification_version: 2
|
60
|
+
summary: RightScale's robust HTTP/S connection module
|
61
|
+
test_files: []
|
55
62
|
|