right_http_connection 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
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