persistent_http 1.0.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f9ee404e0c66d58e123b284244bb4ff73ebae344
4
- data.tar.gz: fc850b407449aee15a7928bfc36275c51bff45e2
3
+ metadata.gz: 58881dc6c2590c4313047e0c9ec21be8be5bb36f
4
+ data.tar.gz: ea99f7c8acf7fb797dcfc6ad26a24a7a8a722628
5
5
  SHA512:
6
- metadata.gz: c2fc446787f29eb14b7a342434b82fc103baa39e4c58f3e19ed6b105d70e8d11ca1cc219ca977fe4aec0fa1a06eb401d401aebda04bd18ede41f9ee3a84f05be
7
- data.tar.gz: 21be4d18ec9d44bbc1e3838b8e445c5940be21684d8f196fe357e112247ee0b56416a7c89ec879ac4c5fedbc80f2fcf63a66ab328c0c2f6dbd816462afd4b9a2
6
+ metadata.gz: 28e48614043b1e6254ee6c861bcf8bf224462cac3a1be5174b4293b1cd6a24d1638bc12af82552187b573f6514875948a5ef8fff61a4f23261752a6bd2936392
7
+ data.tar.gz: 21eaea07a9f7a1e26d309374aaa70c7ecb6a3d01ffc052e3e8637306cb97a41dbae3846b3086e6288e94618af0d61d0fc1e8b017adf50845876d5153c65a50e5
@@ -1,7 +1,5 @@
1
- require 'net/http'
2
- require 'net/https'
3
- require 'persistent_http/faster'
4
- require 'uri'
1
+ require 'persistent_http/connection'
2
+ require 'persistent_http/version'
5
3
  require 'gene_pool'
6
4
 
7
5
  ##
@@ -22,12 +20,12 @@ require 'gene_pool'
22
20
  # :force_retry => true,
23
21
  # :url => 'https://www.example.com/echo/foo' # equivalent to :use_ssl => true, :host => 'www.example.com', :default_path => '/echo/foo'
24
22
  # )
25
- #
23
+ #
26
24
  # def send_get_message
27
25
  # response = @@persistent_http.request
28
26
  # ... Handle response as you would a normal Net::HTTPResponse ...
29
27
  # end
30
- #
28
+ #
31
29
  # def send_post_message
32
30
  # request = Net::HTTP::Post.new('/perform_service)
33
31
  # ... Modify request as needed ...
@@ -37,66 +35,16 @@ require 'gene_pool'
37
35
 
38
36
  class PersistentHTTP
39
37
 
40
- ##
41
- # The version of PersistentHTTP use are using
42
- VERSION = '1.0.0'
43
-
44
38
  ##
45
39
  # Error class for errors raised by PersistentHTTP. Various
46
40
  # SystemCallErrors are re-raised with a human-readable message under this
47
41
  # class.
48
42
  class Error < StandardError; end
49
43
 
50
- ##
51
- # An SSL certificate authority. Setting this will set verify_mode to
52
- # VERIFY_PEER.
53
- attr_accessor :ca_file
54
-
55
- ##
56
- # This client's OpenSSL::X509::Certificate
57
- attr_accessor :certificate
58
-
59
- ##
60
- # Sends debug_output to this IO via Net::HTTP#set_debug_output.
61
- #
62
- # Never use this method in production code, it causes a serious security
63
- # hole.
64
- attr_accessor :debug_output
65
-
66
- ##
67
- # Default path for the request
68
- attr_accessor :default_path
69
-
70
- ##
71
- # Retry even for non-idempotent (POST) requests.
72
- attr_accessor :force_retry
73
-
74
- ##
75
- # Headers that are added to every request
76
- attr_accessor :headers
77
-
78
- ##
79
- # Host for the Net:HTTP connection
80
- attr_reader :host
81
-
82
- ##
83
- # HTTP version to enable version specific features.
84
- attr_reader :http_version
85
-
86
44
  ##
87
45
  # Connection will be renewed if it hasn't been used in this amount of time. Defaults to 10 seconds.
88
46
  attr_reader :idle_timeout
89
47
 
90
- ##
91
- # The value sent in the Keep-Alive header. Defaults to 30. Not needed for
92
- # HTTP/1.1 servers.
93
- #
94
- # This may not work correctly for HTTP/1.0 servers
95
- #
96
- # This method may be removed in a future version as RFC 2616 does not
97
- # require this header.
98
- attr_accessor :keep_alive
99
-
100
48
  ##
101
49
  # Logger for message logging.
102
50
  attr_accessor :logger
@@ -109,47 +57,13 @@ class PersistentHTTP
109
57
  ##
110
58
  # Seconds to wait for an available connection before a Timeout::Error is raised
111
59
  attr_accessor :pool_timeout
112
- ##
113
- # Seconds to wait until a connection is opened. See Net::HTTP#open_timeout
114
- attr_accessor :open_timeout
115
60
 
116
61
  ##
117
62
  # The maximum size of the connection pool
118
63
  attr_reader :pool_size
119
64
 
120
65
  ##
121
- # Port for the Net:HTTP connection
122
- attr_reader :port
123
-
124
- ##
125
- # This client's SSL private key
126
- attr_accessor :private_key
127
-
128
- ##
129
- # The URL through which requests will be proxied
130
- attr_reader :proxy_uri
131
-
132
- ##
133
- # Seconds to wait until reading one block. See Net::HTTP#read_timeout
134
- attr_accessor :read_timeout
135
-
136
- ##
137
- # Use ssl if set
138
- attr_reader :use_ssl
139
-
140
- ##
141
- # SSL verification callback. Used when ca_file is set.
142
- attr_accessor :verify_callback
143
-
144
- ##
145
- # HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_NONE which ignores
146
- # certificate problems.
147
- #
148
- # You can use +verify_mode+ to override any default values.
149
- attr_accessor :verify_mode
150
-
151
- ##
152
- # The threshold in seconds for checking out a connection at which a warning
66
+ # The threshold in seconds for checking out a connection at which a warning
153
67
  # will be logged via the logger
154
68
  attr_reader :warn_timeout
155
69
 
@@ -172,92 +86,21 @@ class PersistentHTTP
172
86
 
173
87
  def initialize(options={})
174
88
  @name = options[:name] || 'PersistentHTTP'
175
- @ca_file = options[:ca_file]
176
- @certificate = options[:certificate]
177
- @debug_output = options[:debug_output]
178
- @default_path = options[:default_path]
179
- @force_retry = options[:force_retry]
180
- @headers = options[:header] || {}
181
- @host = options[:host]
182
89
  @idle_timeout = options[:idle_timeout] || 10
183
- @keep_alive = options[:keep_alive] || 30
184
90
  @logger = options[:logger]
185
91
  @pool_timeout = options[:pool_timeout]
186
- @open_timeout = options[:open_timeout]
187
92
  @pool_size = options[:pool_size] || 1
188
- @port = options[:port]
189
- @private_key = options[:private_key]
190
- @read_timeout = options[:read_timeout]
191
- @use_ssl = options[:use_ssl]
192
- @verify_callback = options[:verify_callback]
193
- @verify_mode = options[:verify_mode]
194
93
  @warn_timeout = options[:warn_timeout] || 0.5
195
-
196
- url = options[:url]
197
- if url
198
- url = URI.parse(url) if url.kind_of? String
199
- @default_path ||= url.request_uri
200
- @host ||= url.host
201
- @port ||= url.port
202
- @use_ssl ||= url.scheme == 'https'
203
- end
204
-
205
- @port ||= (@use_ssl ? 443 : 80)
206
-
207
- # Hash containing the request counts based on the connection
208
- @count_hash = Hash.new(0)
209
-
210
- raise 'host not set' unless @host
211
- net_http_args = [@host, @port]
212
- connection_id = net_http_args.join ':'
213
-
214
- proxy = options[:proxy]
215
-
216
- @proxy_uri = case proxy
217
- when :ENV then proxy_from_env
218
- when URI::HTTP then proxy
219
- when nil then # ignore
220
- else raise ArgumentError, 'proxy must be :ENV or a URI::HTTP'
221
- end
222
94
 
223
- if @proxy_uri then
224
- @proxy_args = [
225
- @proxy_uri.host,
226
- @proxy_uri.port,
227
- @proxy_uri.user,
228
- @proxy_uri.password,
229
- ]
230
-
231
- @proxy_connection_id = [nil, *@proxy_args].join ':'
232
-
233
- connection_id << @proxy_connection_id
234
- net_http_args.concat @proxy_args
235
- end
236
-
237
- @pool = GenePool.new(:name => name + '-' + connection_id,
95
+ @pool = GenePool.new(:name => name,
238
96
  :pool_size => @pool_size,
239
97
  :timeout => @pool_timeout,
240
98
  :warn_timeout => @warn_timeout,
241
99
  :idle_timeout => @idle_timeout,
242
- :close_proc => nil,
100
+ :close_proc => :finish,
243
101
  :logger => @logger) do
244
- begin
245
- @logger.debug { "#{name}: Creating connection" } if @logger
246
- connection = Net::HTTP.new(*net_http_args)
247
- connection.set_debug_output @debug_output if @debug_output
248
- connection.open_timeout = @open_timeout if @open_timeout
249
- connection.read_timeout = @read_timeout if @read_timeout
250
-
251
- ssl connection if @use_ssl
252
-
253
- connection.start
254
- @logger.debug { "#{name} #{connection}: Connection created" } if @logger
255
- connection
256
- rescue Errno::ECONNREFUSED
257
- raise Error, "connection refused: #{connection.address}:#{connection.port}"
258
- rescue Errno::EHOSTDOWN
259
- raise Error, "host down: #{connection.address}:#{connection.port}"
260
- end
102
+ @logger.debug { "#{name}: Creating connection" } if @logger
103
+ Connection.new(options)
261
104
  end
262
105
  end
263
106
 
@@ -284,61 +127,12 @@ class PersistentHTTP
284
127
  # it will be retried automatically.
285
128
 
286
129
  def request(req = nil, options = {}, &block)
287
- retried = false
288
- bad_response = false
289
-
290
- req = Net::HTTP::Get.new @default_path unless req
291
-
292
- headers.each do |pair|
293
- req.add_field(*pair)
294
- end
295
-
296
- req.add_field 'Connection', 'keep-alive'
297
- req.add_field 'Keep-Alive', @keep_alive
298
-
299
130
  @pool.with_connection do |connection|
300
131
  begin
301
- options.each do |key, value|
302
- connection.send("#{key}=", value)
303
- end
304
- response = connection.request req, &block
305
- @http_version ||= response.http_version
306
- @count_hash[connection.object_id] += 1
307
- return response
308
-
309
- rescue Timeout::Error => e
310
- due_to = "(due to #{e.message} - #{e.class})"
311
- message = error_message connection
312
- @logger.info "#{name}: Removing connection #{due_to} #{message}" if @logger
313
- remove connection
132
+ connection.request req, options, &block
133
+ rescue Exception => e
134
+ @pool.remove(connection)
314
135
  raise
315
-
316
- rescue Net::HTTPBadResponse => e
317
- message = error_message connection
318
- if bad_response or not (idempotent? req or @force_retry)
319
- @logger.info "#{name}: Removing connection because of too many bad responses #{message}" if @logger
320
- remove connection
321
- raise Error, "too many bad responses #{message}"
322
- else
323
- bad_response = true
324
- @logger.info "#{name}: Renewing connection because of bad response #{message}" if @logger
325
- connection = renew connection
326
- retry
327
- end
328
-
329
- rescue IOError, EOFError, Errno::ECONNABORTED, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EPIPE => e
330
- due_to = "(due to #{e.message} - #{e.class})"
331
- message = error_message connection
332
- if retried or not (idempotent? req or @force_retry)
333
- @logger.info "#{name}: Removing connection #{due_to} #{message}" if @logger
334
- remove connection
335
- raise Error, "too many connection resets #{due_to} #{message}"
336
- else
337
- retried = true
338
- @logger.info "#{name}: Renewing connection #{due_to} #{message}" if @logger
339
- connection = renew connection
340
- retry
341
- end
342
136
  end
343
137
  end
344
138
  end
@@ -348,121 +142,4 @@ class PersistentHTTP
348
142
  def shutdown(timeout=10)
349
143
  @pool.close(timeout)
350
144
  end
351
-
352
- #######
353
- private
354
- #######
355
-
356
- ##
357
- # Returns an error message containing the number of requests performed on
358
- # this connection
359
-
360
- def error_message connection
361
- requests = @count_hash[connection.object_id] || 0
362
- "after #{requests} requests on #{connection.object_id}"
363
- end
364
-
365
- ##
366
- # URI::escape wrapper
367
-
368
- def escape str
369
- URI.escape str if str
370
- end
371
-
372
- ##
373
- # Finishes the Net::HTTP +connection+
374
-
375
- def finish connection
376
- @count_hash.delete(connection.object_id)
377
- connection.finish
378
- rescue IOError
379
- end
380
-
381
- ##
382
- # Is +req+ idempotent according to RFC 2616?
383
-
384
- def idempotent? req
385
- case req
386
- when Net::HTTP::Delete, Net::HTTP::Get, Net::HTTP::Head,
387
- Net::HTTP::Options, Net::HTTP::Put, Net::HTTP::Trace then
388
- true
389
- end
390
- end
391
-
392
- ##
393
- # Adds "http://" to the String +uri+ if it is missing.
394
-
395
- def normalize_uri uri
396
- (uri =~ /^https?:/) ? uri : "http://#{uri}"
397
- end
398
-
399
- ##
400
- # Creates a URI for an HTTP proxy server from ENV variables.
401
- #
402
- # If +HTTP_PROXY+ is set a proxy will be returned.
403
- #
404
- # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the URI is given the
405
- # indicated user and password unless HTTP_PROXY contains either of these in
406
- # the URI.
407
- #
408
- # For Windows users lowercase ENV variables are preferred over uppercase ENV
409
- # variables.
410
-
411
- def proxy_from_env
412
- env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
413
-
414
- return nil if env_proxy.nil? or env_proxy.empty?
415
-
416
- uri = URI.parse(normalize_uri(env_proxy))
417
-
418
- unless uri.user or uri.password then
419
- uri.user = escape ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER']
420
- uri.password = escape ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS']
421
- end
422
-
423
- uri
424
- end
425
-
426
- ##
427
- # Finishes then removes the Net::HTTP +connection+
428
-
429
- def remove connection
430
- finish connection
431
- @pool.remove(connection)
432
- end
433
-
434
- ##
435
- # Finishes then renews the Net::HTTP +connection+. It may be unnecessary
436
- # to completely recreate the connection but connections that get timed out
437
- # in JRuby leave the ssl context in a frozen object state.
438
-
439
- def renew connection
440
- finish connection
441
- connection = @pool.renew(connection)
442
- end
443
-
444
- ##
445
- # Enables SSL on +connection+
446
-
447
- def ssl connection
448
- connection.use_ssl = true
449
-
450
- # suppress warning but allow override
451
- connection.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @verify_mode
452
-
453
- if @ca_file then
454
- connection.ca_file = @ca_file
455
- connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
456
- connection.verify_callback = @verify_callback if @verify_callback
457
- end
458
-
459
- if @certificate and @private_key then
460
- connection.cert = @certificate
461
- connection.key = @private_key
462
- end
463
-
464
- connection.verify_mode = @verify_mode if @verify_mode
465
- end
466
-
467
145
  end
468
-
@@ -0,0 +1,384 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+
5
+ ##
6
+ # Simplified frontend for Net::HTTP
7
+ #
8
+ # Example:
9
+ #
10
+ # @http = PersistentHTTP::Connection.new(
11
+ # :logger => Rails.logger,
12
+ # :force_retry => true,
13
+ # :url => 'https://www.example.com/echo/foo' # equivalent to :use_ssl => true, :host => 'www.example.com', :default_path => '/echo/foo'
14
+ # )
15
+ #
16
+ # def send_get_message
17
+ # response = @http.request
18
+ # ... Handle response as you would a normal Net::HTTPResponse ...
19
+ # end
20
+ #
21
+ # def send_post_message
22
+ # request = Net::HTTP::Post.new('/perform_service)
23
+ # ... Modify request as needed ...
24
+ # response = @http.request(request)
25
+ # ... Handle response as you would a normal Net::HTTPResponse ...
26
+ # end
27
+
28
+ class PersistentHTTP
29
+ class Connection
30
+
31
+ ##
32
+ # An SSL certificate authority. Setting this will set verify_mode to
33
+ # VERIFY_PEER.
34
+ attr_accessor :ca_file
35
+
36
+ ##
37
+ # This client's OpenSSL::X509::Certificate
38
+ attr_accessor :certificate
39
+
40
+ ##
41
+ # Sends debug_output to this IO via Net::HTTP#set_debug_output.
42
+ #
43
+ # Never use this method in production code, it causes a serious security
44
+ # hole.
45
+ attr_accessor :debug_output
46
+
47
+ ##
48
+ # Default path for the request
49
+ attr_accessor :default_path
50
+
51
+ ##
52
+ # Retry even for non-idempotent (POST) requests.
53
+ attr_accessor :force_retry
54
+
55
+ ##
56
+ # Headers that are added to every request
57
+ attr_accessor :headers
58
+
59
+ ##
60
+ # Host for the Net:HTTP connection
61
+ attr_reader :host
62
+
63
+ ##
64
+ # HTTP version to enable version specific features.
65
+ attr_reader :http_version
66
+
67
+ ##
68
+ # The value sent in the Keep-Alive header. Defaults to 30. Not needed for
69
+ # HTTP/1.1 servers.
70
+ #
71
+ # This may not work correctly for HTTP/1.0 servers
72
+ #
73
+ # This method may be removed in a future version as RFC 2616 does not
74
+ # require this header.
75
+ attr_accessor :keep_alive
76
+
77
+ ##
78
+ # Logger for message logging.
79
+ attr_accessor :logger
80
+
81
+ ##
82
+ # A name for this connection. Allows you to keep your connections apart
83
+ # from everybody else's.
84
+ attr_reader :name
85
+
86
+ ##
87
+ # Seconds to wait until a connection is opened. See Net::HTTP#open_timeout
88
+ attr_accessor :open_timeout
89
+
90
+ ##
91
+ # Port for the Net:HTTP connection
92
+ attr_reader :port
93
+
94
+ ##
95
+ # This client's SSL private key
96
+ attr_accessor :private_key
97
+
98
+ ##
99
+ # The URL through which requests will be proxied
100
+ attr_reader :proxy_uri
101
+
102
+ ##
103
+ # Seconds to wait until reading one block. See Net::HTTP#read_timeout
104
+ attr_accessor :read_timeout
105
+
106
+ ##
107
+ # Use ssl if set
108
+ attr_reader :use_ssl
109
+
110
+ ##
111
+ # SSL verification callback. Used when ca_file is set.
112
+ attr_accessor :verify_callback
113
+
114
+ ##
115
+ # HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_NONE which ignores
116
+ # certificate problems.
117
+ #
118
+ # You can use +verify_mode+ to override any default values.
119
+ attr_accessor :verify_mode
120
+
121
+ ##
122
+ # Creates a new HTTP Connection.
123
+ #
124
+ # Set +name+ to keep your connections apart from everybody else's. Not
125
+ # required currently, but highly recommended. Your library name should be
126
+ # good enough. This parameter will be required in a future version.
127
+ #
128
+ # +proxy+ may be set to a URI::HTTP or :ENV to pick up proxy options from
129
+ # the environment. See proxy_from_env for details.
130
+ #
131
+ # In order to use a URI for the proxy you'll need to do some extra work
132
+ # beyond URI.parse:
133
+ #
134
+ # proxy = URI.parse 'http://proxy.example'
135
+ # proxy.user = 'AzureDiamond'
136
+ # proxy.password = 'hunter2'
137
+
138
+ def initialize(options={})
139
+ @name = options[:name] || 'PeristentHTTP::Connection'
140
+ @ca_file = options[:ca_file]
141
+ @certificate = options[:certificate]
142
+ @debug_output = options[:debug_output]
143
+ @default_path = options[:default_path]
144
+ @force_retry = options[:force_retry]
145
+ @headers = options[:header] || {}
146
+ @host = options[:host]
147
+ @keep_alive = options[:keep_alive] || 30
148
+ @logger = options[:logger]
149
+ @port = options[:port]
150
+ @private_key = options[:private_key]
151
+ @open_timeout = options[:open_timeout]
152
+ @read_timeout = options[:read_timeout]
153
+ @use_ssl = options[:use_ssl]
154
+ @verify_callback = options[:verify_callback]
155
+ @verify_mode = options[:verify_mode]
156
+ # Because maybe we want a non-persistent connection and are just using this for the proxy stuff
157
+ @non_persistent = options[:non_persistent]
158
+
159
+ url = options[:url]
160
+ if url
161
+ url = URI.parse(url) if url.kind_of? String
162
+ @default_path ||= url.request_uri
163
+ @host ||= url.host
164
+ @port ||= url.port
165
+ @use_ssl ||= url.scheme == 'https'
166
+ end
167
+
168
+ @port ||= (@use_ssl ? 443 : 80)
169
+
170
+ raise 'host not set' unless @host
171
+ @net_http_args = [@host, @port]
172
+
173
+ proxy = options[:proxy]
174
+ @proxy_uri = case proxy
175
+ when :ENV then proxy_from_env
176
+ when URI::HTTP then proxy
177
+ when nil then # ignore
178
+ else raise ArgumentError, 'proxy must be :ENV or a URI::HTTP'
179
+ end
180
+
181
+ if @proxy_uri then
182
+ @proxy_args = [
183
+ @proxy_uri.host,
184
+ @proxy_uri.port,
185
+ @proxy_uri.user,
186
+ @proxy_uri.password,
187
+ ]
188
+
189
+ @net_http_args.concat @proxy_args
190
+ end
191
+
192
+ @name += ':' + @net_http_args.join(':')
193
+ @logger.debug { "#{@name}: Creating connection" } if @logger
194
+ renew
195
+ end
196
+
197
+ def renew
198
+ finish if @connection
199
+ @message_count = 0
200
+ @connection = Net::HTTP.new(*@net_http_args)
201
+ @connection.set_debug_output @debug_output if @debug_output
202
+ @connection.open_timeout = @open_timeout if @open_timeout
203
+ @connection.read_timeout = @read_timeout if @read_timeout
204
+
205
+ ssl if @use_ssl
206
+
207
+ @connection.start
208
+ @logger.debug { "#{@name} #{@connection}: Connection created" } if @logger
209
+ rescue Errno::ECONNREFUSED
210
+ raise Error, "connection refused: #{@connection.address}:#{@connection.port}"
211
+ rescue Errno::EHOSTDOWN
212
+ raise Error, "host down: #{@connection.address}:#{@connection.port}"
213
+ end
214
+
215
+ ##
216
+ # Makes a request per +req+. If +req+ is nil a Net::HTTP::Get is performed
217
+ # against +default_path+.
218
+ #
219
+ # If a block is passed #request behaves like Net::HTTP#request (the body of
220
+ # the response will not have been read).
221
+ #
222
+ # +req+ must be a Net::HTTPRequest subclass (see Net::HTTP for a list).
223
+ #
224
+ # If there is an error and the request is idempontent according to RFC 2616
225
+ # it will be retried automatically.
226
+
227
+ def request(req = nil, options = {}, &block)
228
+ retried = false
229
+ bad_response = false
230
+
231
+ req = Net::HTTP::Get.new @default_path unless req
232
+
233
+ headers.each do |pair|
234
+ req.add_field(*pair)
235
+ end
236
+
237
+ unless @non_persistent
238
+ req.add_field 'Connection', 'keep-alive'
239
+ req.add_field 'Keep-Alive', @keep_alive
240
+ end
241
+
242
+ begin
243
+ options.each do |key, value|
244
+ @connection.send("#{key}=", value)
245
+ end
246
+ response = @connection.request req, &block
247
+ @http_version ||= response.http_version
248
+ @message_count += 1
249
+ return response
250
+
251
+ rescue Timeout::Error => e
252
+ due_to = "(due to #{e.message} - #{e.class})"
253
+ @logger.info "#{@name}: Removing connection #{due_to} #{error_message}" if @logger
254
+ finish
255
+ raise
256
+
257
+ rescue Net::HTTPBadResponse => e
258
+ if bad_response or not (idempotent? req or @force_retry)
259
+ @logger.info "#{@name}: Removing connection because of too many bad responses #{error_message}" if @logger
260
+ finish
261
+ raise Error, "too many bad responses #{error_message}"
262
+ else
263
+ bad_response = true
264
+ @logger.info "#{@name}: Renewing connection because of bad response #{error_message}" if @logger
265
+ renew
266
+ retry
267
+ end
268
+
269
+ rescue IOError, EOFError, Errno::ECONNABORTED, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EPIPE => e
270
+ due_to = "(due to #{e.message} - #{e.class})"
271
+ if retried or not (idempotent? req or @force_retry)
272
+ @logger.info "#{@name}: Removing connection #{due_to} #{error_message}" if @logger
273
+ finish
274
+ raise Error, "too many connection resets #{due_to} #{error_message}"
275
+ else
276
+ retried = true
277
+ @logger.info "#{@name}: Renewing connection #{due_to} #{error_message}" if @logger
278
+ renew
279
+ retry
280
+ end
281
+ end
282
+ end
283
+
284
+ ##
285
+ # Finishes the Net::HTTP +connection+
286
+
287
+ def finish
288
+ @connection.finish
289
+ rescue IOError
290
+ end
291
+
292
+ def to_s
293
+ @name
294
+ end
295
+
296
+ #######
297
+ private
298
+ #######
299
+
300
+ ##
301
+ # Returns an error message containing the number of requests performed on
302
+ # this connection
303
+
304
+ def error_message
305
+ "after #{@message_count} requests on #{@connection.object_id}"
306
+ end
307
+
308
+ ##
309
+ # URI::escape wrapper
310
+
311
+ def escape str
312
+ URI.escape str if str
313
+ end
314
+
315
+
316
+ ##
317
+ # Is +req+ idempotent according to RFC 2616?
318
+
319
+ def idempotent? req
320
+ case req
321
+ when Net::HTTP::Delete, Net::HTTP::Get, Net::HTTP::Head,
322
+ Net::HTTP::Options, Net::HTTP::Put, Net::HTTP::Trace then
323
+ true
324
+ end
325
+ end
326
+
327
+ ##
328
+ # Adds "http://" to the String +uri+ if it is missing.
329
+
330
+ def normalize_uri uri
331
+ (uri =~ /^https?:/) ? uri : "http://#{uri}"
332
+ end
333
+
334
+ ##
335
+ # Creates a URI for an HTTP proxy server from ENV variables.
336
+ #
337
+ # If +HTTP_PROXY+ is set a proxy will be returned.
338
+ #
339
+ # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the URI is given the
340
+ # indicated user and password unless HTTP_PROXY contains either of these in
341
+ # the URI.
342
+ #
343
+ # For Windows users lowercase ENV variables are preferred over uppercase ENV
344
+ # variables.
345
+
346
+ def proxy_from_env
347
+ env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
348
+
349
+ return nil if env_proxy.nil? or env_proxy.empty?
350
+
351
+ uri = URI.parse(normalize_uri(env_proxy))
352
+
353
+ unless uri.user or uri.password then
354
+ uri.user = escape ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER']
355
+ uri.password = escape ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS']
356
+ end
357
+
358
+ uri
359
+ end
360
+
361
+ ##
362
+ # Enables SSL on +connection+
363
+
364
+ def ssl
365
+ @connection.use_ssl = true
366
+
367
+ # suppress warning but allow override
368
+ @connection.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @verify_mode
369
+
370
+ if @ca_file then
371
+ @connection.ca_file = @ca_file
372
+ @connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
373
+ @connection.verify_callback = @verify_callback if @verify_callback
374
+ end
375
+
376
+ if @certificate and @private_key then
377
+ @connection.cert = @certificate
378
+ @connection.key = @private_key
379
+ end
380
+
381
+ @connection.verify_mode = @verify_mode if @verify_mode
382
+ end
383
+ end
384
+ end
@@ -0,0 +1,3 @@
1
+ class PersistentHTTP #:nodoc
2
+ VERSION = '2.0.0'
3
+ end
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: persistent_http
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Pardee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-11 00:00:00.000000000 Z
11
+ date: 2014-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gene_pool
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  description: Persistent HTTP connections using a connection pool
@@ -31,12 +31,13 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - lib/persistent_http/faster.rb
35
- - lib/persistent_http.rb
36
- - LICENSE
37
- - Rakefile
38
34
  - History.md
35
+ - LICENSE
39
36
  - README.rdoc
37
+ - Rakefile
38
+ - lib/persistent_http.rb
39
+ - lib/persistent_http/connection.rb
40
+ - lib/persistent_http/version.rb
40
41
  homepage: http://github.com/bpardee/persistent_http
41
42
  licenses: []
42
43
  metadata: {}
@@ -46,17 +47,17 @@ require_paths:
46
47
  - lib
47
48
  required_ruby_version: !ruby/object:Gem::Requirement
48
49
  requirements:
49
- - - '>='
50
+ - - ">="
50
51
  - !ruby/object:Gem::Version
51
52
  version: '0'
52
53
  required_rubygems_version: !ruby/object:Gem::Requirement
53
54
  requirements:
54
- - - '>='
55
+ - - ">="
55
56
  - !ruby/object:Gem::Version
56
57
  version: '0'
57
58
  requirements: []
58
59
  rubyforge_project:
59
- rubygems_version: 2.0.2
60
+ rubygems_version: 2.2.2
60
61
  signing_key:
61
62
  specification_version: 4
62
63
  summary: Persistent HTTP connections using a connection pool
@@ -1,27 +0,0 @@
1
- require 'net/protocol'
2
-
3
- ##
4
- # Aaron Patterson's monkeypatch (accepted into 1.9.1) to fix Net::HTTP's speed
5
- # problems.
6
- #
7
- # http://gist.github.com/251244
8
-
9
- class Net::BufferedIO #:nodoc:
10
- alias :old_rbuf_fill :rbuf_fill
11
-
12
- def rbuf_fill
13
- if @io.respond_to? :read_nonblock then
14
- begin
15
- @rbuf << @io.read_nonblock(65536)
16
- rescue Errno::EWOULDBLOCK => e
17
- retry if IO.select [@io], nil, nil, @read_timeout
18
- raise Timeout::Error, e.message
19
- end
20
- else # SSL sockets do not have read_nonblock
21
- timeout @read_timeout do
22
- @rbuf << @io.sysread(65536)
23
- end
24
- end
25
- end
26
- end if RUBY_VERSION < '1.9'
27
-