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.
Files changed (4) hide show
  1. data/History.txt +11 -1
  2. data/README.txt +1 -1
  3. data/lib/right_http_connection.rb +88 -36
  4. metadata +42 -35
@@ -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
@@ -28,7 +28,7 @@ algorithm for low-level network errors.
28
28
 
29
29
  == INSTALL:
30
30
 
31
- sudo gem install
31
+ sudo gem install right_http_connection
32
32
 
33
33
  == LICENSE:
34
34
 
@@ -34,7 +34,7 @@ module RightHttpConnection #:nodoc:
34
34
  module VERSION #:nodoc:
35
35
  MAJOR = 1
36
36
  MINOR = 2
37
- TINY = 1
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 = 30
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
- # Params hash
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
- =begin rdoc
119
- Params hash:
120
- :user_agent => 'www.HostName.com' String to report as HTTP User agent
121
- :ca_file => 'path_to_file' A path of a CA certification file in PEM format. The file can contain several CA certificates.
122
- :logger => Logger object If omitted, HttpConnection logs to STDOUT
123
- :exception => Exception to raise The type of exception to raise if a request repeatedly fails. RuntimeError is raised if this parameter is omitted.
124
-
125
- =end
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 HTTP_CONNECTION_RETRY_DELAY seconds
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-HTTP_CONNECTION_RETRY_DELAY) > @@eof[@server].last.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 = HTTP_CONNECTION_OPEN_TIMEOUT
246
- @http.read_timeout = HTTP_CONNECTION_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 > HTTP_CONNECTION_RETRY_COUNT \
286
- && error_time + HTTP_CONNECTION_RETRY_DELAY > Time.now
287
- @logger.warn("#{err_header} re-raising same error: #{banana_message} " +
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(banana_message)
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
- if(request.body && request.body.respond_to?(:read))
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.1
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
- test_files: []
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
- extra_rdoc_files:
45
- - History.txt
46
- - Manifest.txt
47
- - README.txt
48
- executables: []
49
-
50
- extensions: []
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
- dependencies: []
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