right_http_connection 1.2.3 → 1.2.4

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 +8 -1
  2. data/Rakefile +18 -5
  3. data/lib/right_http_connection.rb +54 -54
  4. metadata +6 -6
@@ -49,4 +49,11 @@ Initial public release
49
49
 
50
50
  - Added support for setting retry & timeout parameters in the constructor
51
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
52
+ the seek pointer for the subsequent re-request
53
+
54
+ == 1.2.4
55
+
56
+ * r4984, konstantin, 2008-08-11 14:49:18 +0400
57
+ * fixed a bug: <NoMethodError: You have a nil object when you didn't expect it!
58
+ The error occurred while evaluating nil.body_stream>
59
+
data/Rakefile CHANGED
@@ -12,10 +12,10 @@ include FileUtils
12
12
  require File.join(File.dirname(__FILE__), 'lib', 'right_http_connection')
13
13
 
14
14
  AUTHOR = 'RightScale' # can also be an array of Authors
15
- EMAIL = "support@rightscale.com"
15
+ EMAIL = "rubygems@rightscale.com"
16
16
  DESCRIPTION = "RightScale's robust HTTP/S connection module"
17
17
  GEM_NAME = 'right_http_connection' # what ppl will type to install your gem
18
- RUBYFORGE_PROJECT = 'rightaws' # The unix name for your project
18
+ RUBYFORGE_PROJECT = 'rightscale' # The unix name for your project
19
19
  HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
20
20
  DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
21
21
 
@@ -29,10 +29,23 @@ RDOC_OPTS = ['--quiet', '--title', 'right_http_connection documentation',
29
29
  "--main", "README",
30
30
  "--inline-source"]
31
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....
32
38
  class Hoe
33
- def extra_deps
34
- @extra_deps.reject { |x| Array(x).first == 'hoe' }
35
- end
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
36
49
  end
37
50
 
38
51
  # Generate all the Rake tasks
@@ -34,7 +34,7 @@ module RightHttpConnection #:nodoc:
34
34
  module VERSION #:nodoc:
35
35
  MAJOR = 1
36
36
  MINOR = 2
37
- TINY = 3
37
+ TINY = 4
38
38
 
39
39
  STRING = [MAJOR, MINOR, TINY].join('.')
40
40
  end
@@ -42,7 +42,7 @@ end
42
42
 
43
43
 
44
44
  module Rightscale
45
-
45
+
46
46
  =begin rdoc
47
47
  HttpConnection maintains a persistent HTTP connection to a remote
48
48
  server. Each instance maintains its own unique connection to the
@@ -75,16 +75,16 @@ the full number of potential reconnects and retries available to
75
75
  them.
76
76
  =end
77
77
 
78
- class HttpConnection
78
+ class HttpConnection
79
79
 
80
80
  # Number of times to retry the request after encountering the first error
81
- HTTP_CONNECTION_RETRY_COUNT = 3
81
+ HTTP_CONNECTION_RETRY_COUNT = 3
82
82
  # Throw a Timeout::Error if a connection isn't established within this number of seconds
83
- HTTP_CONNECTION_OPEN_TIMEOUT = 5
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 = 120
86
- # Length of the post-error probationary period during which all requests will fail
87
- HTTP_CONNECTION_RETRY_DELAY = 15
85
+ HTTP_CONNECTION_READ_TIMEOUT = 120
86
+ # Length of the post-error probationary period during which all requests will fail
87
+ HTTP_CONNECTION_RETRY_DELAY = 15
88
88
 
89
89
  #--------------------
90
90
  # class methods
@@ -95,10 +95,10 @@ them.
95
95
  @@params[:http_connection_open_timeout] = HTTP_CONNECTION_OPEN_TIMEOUT
96
96
  @@params[:http_connection_read_timeout] = HTTP_CONNECTION_READ_TIMEOUT
97
97
  @@params[:http_connection_retry_delay] = HTTP_CONNECTION_RETRY_DELAY
98
-
98
+
99
99
  # Query the global (class-level) parameters:
100
- #
101
- # :user_agent => 'www.HostName.com' # String to report as HTTP User agent
100
+ #
101
+ # :user_agent => 'www.HostName.com' # String to report as HTTP User agent
102
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
103
  # :logger => Logger object # If omitted, HttpConnection logs to STDOUT
104
104
  # :exception => Exception to raise # The type of exception to raise
@@ -110,7 +110,7 @@ them.
110
110
  def self.params
111
111
  @@params
112
112
  end
113
-
113
+
114
114
  # Set the global (class-level) parameters
115
115
  def self.params=(params)
116
116
  @@params = params
@@ -125,7 +125,7 @@ them.
125
125
  attr_accessor :logger
126
126
 
127
127
  # Params hash:
128
- # :user_agent => 'www.HostName.com' # String to report as HTTP User agent
128
+ # :user_agent => 'www.HostName.com' # String to report as HTTP User agent
129
129
  # :ca_file => 'path_to_file' # A path of a CA certification file in PEM format. The file can contain several CA certificates.
130
130
  # :logger => Logger object # If omitted, HttpConnection logs to STDOUT
131
131
  # :exception => Exception to raise # The type of exception to raise if a request repeatedly fails. RuntimeError is raised if this parameter is omitted.
@@ -142,7 +142,7 @@ them.
142
142
  @params[:http_connection_retry_delay] ||= @@params[:http_connection_retry_delay]
143
143
  @http = nil
144
144
  @server = nil
145
- @logger = get_param(:logger) ||
145
+ @logger = get_param(:logger) ||
146
146
  (RAILS_DEFAULT_LOGGER if defined?(RAILS_DEFAULT_LOGGER)) ||
147
147
  Logger.new(STDOUT)
148
148
  end
@@ -164,7 +164,7 @@ them.
164
164
  def socket_read_size=(newsize)
165
165
  Net::BufferedIO.socket_read_size=(newsize)
166
166
  end
167
-
167
+
168
168
  # Query for the maximum size (in bytes) of a single read from local data
169
169
  # sources like files. This is important, for example, in a streaming PUT of a
170
170
  # large buffer.
@@ -190,27 +190,27 @@ them.
190
190
  def error_count
191
191
  @@state[@server] ? @@state[@server][:count] : 0
192
192
  end
193
-
193
+
194
194
  # time of last error for server, nil if all is ok
195
195
  def error_time
196
196
  @@state[@server] && @@state[@server][:time]
197
197
  end
198
-
198
+
199
199
  # message for last error for server, "" if all is ok
200
200
  def error_message
201
201
  @@state[@server] ? @@state[@server][:message] : ""
202
202
  end
203
-
203
+
204
204
  # add an error for a server
205
205
  def error_add(message)
206
206
  @@state[@server] = { :count => error_count+1, :time => Time.now, :message => message }
207
207
  end
208
-
208
+
209
209
  # reset the error state for a server (i.e. a request succeeded)
210
210
  def error_reset
211
211
  @@state.delete(@server)
212
212
  end
213
-
213
+
214
214
  # Error message stuff...
215
215
  def banana_message
216
216
  return "#{@server} temporarily unavailable: (#{error_message})"
@@ -219,7 +219,7 @@ them.
219
219
  def err_header
220
220
  return "#{self.class.name} :"
221
221
  end
222
-
222
+
223
223
  # Adds new EOF timestamp.
224
224
  # Returns the number of seconds to wait before new conection retry:
225
225
  # 0.5, 1, 2, 4, 8
@@ -232,29 +232,29 @@ them.
232
232
  def eof_time
233
233
  @@eof[@server] && @@eof[@server].last
234
234
  end
235
-
235
+
236
236
  # Returns true if we are receiving EOFs during last @params[:http_connection_retry_delay] seconds
237
237
  # and there were no successful response from server
238
238
  def raise_on_eof_exception?
239
239
  @@eof[@server].blank? ? false : ( (Time.now.to_i-@params[:http_connection_retry_delay]) > @@eof[@server].last.to_i )
240
- end
241
-
240
+ end
241
+
242
242
  # Reset a list of EOFs for this server.
243
243
  # This is being called when we have got an successful response from server.
244
244
  def eof_reset
245
245
  @@eof.delete(@server)
246
246
  end
247
-
248
- # Detects if an object is 'streamable' - can we read from it, and can we know the size?
247
+
248
+ # Detects if an object is 'streamable' - can we read from it, and can we know the size?
249
249
  def setup_streaming(request)
250
250
  if(request.body && request.body.respond_to?(:read))
251
251
  body = request.body
252
- request.content_length = body.respond_to?(:lstat) ? body.lstat.size : body.size
252
+ request.content_length = body.respond_to?(:lstat) ? body.lstat.size : body.size
253
253
  request.body_stream = request.body
254
254
  true
255
255
  end
256
256
  end
257
-
257
+
258
258
  def get_fileptr_offset(request_params)
259
259
  request_params[:request].body.pos
260
260
  rescue Exception => e
@@ -262,7 +262,7 @@ them.
262
262
  # Just return 0 and get on with life.
263
263
  0
264
264
  end
265
-
265
+
266
266
  def reset_fileptr_offset(request, offset = 0)
267
267
  if(request.body_stream && request.body_stream.respond_to?(:pos))
268
268
  begin
@@ -272,7 +272,7 @@ them.
272
272
  " -- #{err_header} #{e.inspect}")
273
273
  raise e
274
274
  end
275
- end
275
+ end
276
276
  end
277
277
 
278
278
  # Start a fresh connection. The object closes any existing connection and
@@ -284,12 +284,12 @@ them.
284
284
  @server = request_params[:server]
285
285
  @port = request_params[:port]
286
286
  @protocol = request_params[:protocol]
287
-
287
+
288
288
  @logger.info("Opening new #{@protocol.upcase} connection to #@server:#@port")
289
289
  @http = Net::HTTP.new(@server, @port)
290
290
  @http.open_timeout = @params[:http_connection_open_timeout]
291
291
  @http.read_timeout = @params[:http_connection_read_timeout]
292
-
292
+
293
293
  if @protocol == 'https'
294
294
  verifyCallbackProc = Proc.new{ |ok, x509_store_ctx|
295
295
  code = x509_store_ctx.error
@@ -303,7 +303,7 @@ them.
303
303
  if ca_file
304
304
  @http.verify_mode = OpenSSL::SSL::VERIFY_PEER
305
305
  @http.verify_callback = verifyCallbackProc
306
- @http.ca_file = ca_file
306
+ @http.ca_file = ca_file
307
307
  end
308
308
  end
309
309
  # open connection
@@ -312,55 +312,55 @@ them.
312
312
 
313
313
  public
314
314
 
315
- =begin rdoc
315
+ =begin rdoc
316
316
  Send HTTP request to server
317
317
 
318
318
  request_params hash:
319
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
320
+ :port => '80' # Port of HTTP server
321
+ :protocol => 'https' # http and https are supported on any port
322
322
  :request => 'requeststring' # Fully-formed HTTP request to make
323
323
 
324
324
  Raises RuntimeError, Interrupt, and params[:exception] (if specified in new).
325
-
325
+
326
326
  =end
327
327
  def request(request_params, &block)
328
328
  # We save the offset here so that if we need to retry, we can return the file pointer to its initial position
329
329
  mypos = get_fileptr_offset(request_params)
330
330
  loop do
331
331
  # if we are inside a delay between retries: no requests this time!
332
- if error_count > @params[:http_connection_retry_count] &&
332
+ if error_count > @params[:http_connection_retry_count] &&
333
333
  error_time + @params[:http_connection_retry_delay] > Time.now
334
334
  # store the message (otherwise it will be lost after error_reset and
335
335
  # we will raise an exception with an empty text)
336
336
  banana_message_text = banana_message
337
337
  @logger.warn("#{err_header} re-raising same error: #{banana_message_text} " +
338
- "-- error count: #{error_count}, error age: #{Time.now.to_i - error_time.to_i}")
338
+ "-- error count: #{error_count}, error age: #{Time.now.to_i - error_time.to_i}")
339
339
  exception = get_param(:exception) || RuntimeError
340
340
  raise exception.new(banana_message_text)
341
341
  end
342
-
342
+
343
343
  # try to connect server(if connection does not exist) and get response data
344
344
  begin
345
345
  request_params[:protocol] ||= (request_params[:port] == 443 ? 'https' : 'http')
346
+
347
+ request = request_params[:request]
348
+ request['User-Agent'] = get_param(:user_agent) || ''
349
+
346
350
  # (re)open connection to server if none exists or params has changed
347
- unless @http &&
351
+ unless @http &&
348
352
  @http.started? &&
349
353
  @server == request_params[:server] &&
350
354
  @port == request_params[:port] &&
351
355
  @protocol == request_params[:protocol]
352
356
  start(request_params)
353
357
  end
354
-
355
- # get response and return it
356
- request = request_params[:request]
357
- request['User-Agent'] = get_param(:user_agent) || ''
358
358
 
359
359
  # Detect if the body is a streamable object like a file or socket. If so, stream that
360
360
  # bad boy.
361
361
  setup_streaming(request)
362
362
  response = @http.request(request, &block)
363
-
363
+
364
364
  error_reset
365
365
  eof_reset
366
366
  return response
@@ -373,26 +373,26 @@ them.
373
373
  # 'slept'. It is still not clear which way we should treat errors
374
374
  # like RST and resolution failures. For now, there is no additional
375
375
  # delay for these errors although this may change in the future.
376
-
376
+
377
377
  # EOFError means the server closed the connection on us.
378
378
  rescue EOFError => e
379
379
  @logger.debug("#{err_header} server #{@server} closed connection")
380
380
  @http = nil
381
-
381
+
382
382
  # if we have waited long enough - raise an exception...
383
383
  if raise_on_eof_exception?
384
384
  exception = get_param(:exception) || RuntimeError
385
- @logger.warn("#{err_header} raising #{exception} due to permanent EOF being received from #{@server}, error age: #{Time.now.to_i - eof_time.to_i}")
385
+ @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
386
  raise exception.new("Permanent EOF is being received from #{@server}.")
387
387
  else
388
388
  # ... else just sleep a bit before new retry
389
389
  sleep(add_eof)
390
390
  # We will be retrying the request, so reset the file pointer
391
391
  reset_fileptr_offset(request, mypos)
392
- end
392
+ end
393
393
  rescue Exception => e # See comment at bottom for the list of errors seen...
394
394
  @http = nil
395
- # if ctrl+c is pressed - we have to reraise exception to terminate proggy
395
+ # if ctrl+c is pressed - we have to reraise exception to terminate proggy
396
396
  if e.is_a?(Interrupt) && !( e.is_a?(Errno::ETIMEDOUT) || e.is_a?(Timeout::Error))
397
397
  @logger.debug( "#{err_header} request to server #{@server} interrupted by ctrl-c")
398
398
  raise
@@ -407,7 +407,7 @@ them.
407
407
 
408
408
  # We will be retrying the request, so reset the file pointer
409
409
  reset_fileptr_offset(request, mypos)
410
-
410
+
411
411
  end
412
412
  end
413
413
  end
@@ -416,7 +416,7 @@ them.
416
416
  if @http && @http.started?
417
417
  reason = ", reason: '#{reason}'" unless reason.blank?
418
418
  @logger.info("Closing #{@http.use_ssl? ? 'HTTPS' : 'HTTP'} connection to #{@http.address}:#{@http.port}#{reason}")
419
- @http.finish
419
+ @http.finish
420
420
  end
421
421
  end
422
422
 
@@ -430,6 +430,6 @@ them.
430
430
  # #<Errno::ECONNRESET: Connection reset by peer>
431
431
  # #<OpenSSL::SSL::SSLError: SSL_write:: bad write retry>
432
432
  end
433
-
433
+
434
434
  end
435
435
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_http_connection
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - RightScale
@@ -9,12 +9,12 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-27 00:00:00 -07:00
12
+ date: 2009-02-24 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
16
  description: RightScale's robust HTTP/S connection module
17
- email: support@rightscale.com
17
+ email: rubygems@rightscale.com
18
18
  executables: []
19
19
 
20
20
  extensions: []
@@ -32,7 +32,7 @@ files:
32
32
  - lib/right_http_connection.rb
33
33
  - setup.rb
34
34
  has_rdoc: true
35
- homepage: http://rightaws.rubyforge.org
35
+ homepage: http://rightscale.rubyforge.org
36
36
  post_install_message:
37
37
  rdoc_options:
38
38
  - --main
@@ -53,8 +53,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
53
  version:
54
54
  requirements: []
55
55
 
56
- rubyforge_project: rightaws
57
- rubygems_version: 1.0.1
56
+ rubyforge_project: rightscale
57
+ rubygems_version: 1.3.1
58
58
  signing_key:
59
59
  specification_version: 2
60
60
  summary: RightScale's robust HTTP/S connection module