Parent

Class Index [+]

Quicksearch

Net::HTTP::Persistent

Persistent connections for Net::HTTP

Net::HTTP::Persistent maintains persistent connections across all the servers you wish to talk to. For each host:port you communicate with a single persistent connection is created.

Multiple Net::HTTP::Persistent objects will share the same set of connections.

For each thread you start a new connection will be created. A Net::HTTP::Persistent connection will not be shared across threads.

You can shut down the HTTP connections when done by calling #. You should name your Net::HTTP::Persistent object if you intend to call this method.

Example:

  uri = URI.parse 'http://example.com/awesome/web/service'
  http = Net::HTTP::Persistent.new
  stuff = http.request uri # performs a GET

  # perform a POST
  post_uri = uri + 'create'
  post = Net::HTTP::Post.new post_uri.path
  post.set_form_data 'some' => 'cool data'
  http.request post_uri, post # URI is always required

Constants

VERSION

The version of Net::HTTP::Persistent use are using

Attributes

certificate[RW]

This client’s OpenSSL::X509::Certificate

ca_file[RW]

An SSL certificate authority. Setting this will set verify_mode to VERIFY_PEER.

debug_output[RW]

Sends debug_output to this IO via Net::HTTP#set_debug_output.

Never use this method in production code, it causes a serious security hole.

headers[R]

Headers that are added to every request

http_versions[R]

Maps host:port to an HTTP version. This allows us to enable version specific features.

keep_alive[RW]

The value sent in the Keep-Alive header. Defaults to 30. Not needed for HTTP/1.1 servers.

This may not work correctly for HTTP/1.0 servers

This method may be removed in a future version as RFC 2616 does not require this header.

name[R]

A name for this connection. Allows you to keep your connections apart from everybody else’s.

open_timeout[RW]

Seconds to wait until a connection is opened. See Net::HTTP#open_timeout

private_key[RW]

This client’s SSL private key

proxy_uri[R]

The URL through which requests will be proxied

read_timeout[RW]

Seconds to wait until reading one block. See Net::HTTP#read_timeout

verify_callback[RW]

SSL verification callback. Used when ca_file is set.

verify_mode[RW]

HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_NONE which ignores certificate problems.

You can use verify_mode to override any default values.

Public Class Methods

new(name = nil, proxy = nil) click to toggle source

Creates a new Net::HTTP::Persistent.

Set name to keep your connections apart from everybody else’s. Not required currently, but highly recommended. Your library name should be good enough. This parameter will be required in a future version.

proxy may be set to a URI::HTTP or :ENV to pick up proxy options from the environment. See proxy_from_env for details.

In order to use a URI for the proxy you’ll need to do some extra work beyond URI.parse:

  proxy = URI.parse 'http://proxy.example'
  proxy.user     = 'AzureDiamond'
  proxy.password = 'hunter2'
     # File lib/bundler/vendor/net/http/persistent.rb, line 156
156:   def initialize name = nil, proxy = nil
157:     @name = name
158: 
159:     @proxy_uri = case proxy
160:                  when :ENV      then proxy_from_env
161:                  when URI::HTTP then proxy
162:                  when nil       then # ignore
163:                  else raise ArgumentError, 'proxy must be :ENV or a URI::HTTP'
164:                  end
165: 
166:     if @proxy_uri then
167:       @proxy_args = [
168:         @proxy_uri.host,
169:         @proxy_uri.port,
170:         @proxy_uri.user,
171:         @proxy_uri.password,
172:       ]
173: 
174:       @proxy_connection_id = [nil, *@proxy_args].join ':'
175:     end
176: 
177:     @debug_output  = nil
178:     @headers       = {}
179:     @http_versions = {}
180:     @keep_alive    = 30
181:     @open_timeout  = nil
182:     @read_timeout  = nil
183: 
184:     key = ['net_http_persistent', name, 'connections'].compact.join '_'
185:     @connection_key = key.intern
186:     key = ['net_http_persistent', name, 'requests'].compact.join '_'
187:     @request_key    = key.intern
188: 
189:     @certificate     = nil
190:     @ca_file         = nil
191:     @private_key     = nil
192:     @verify_callback = nil
193:     @verify_mode     = nil
194:   end

Public Instance Methods

connection_for(uri) click to toggle source

Creates a new connection for uri

     # File lib/bundler/vendor/net/http/persistent.rb, line 199
199:   def connection_for uri
200:     Thread.current[@connection_key] ||= {}
201:     Thread.current[@request_key]    ||= Hash.new 0
202: 
203:     connections = Thread.current[@connection_key]
204: 
205:     net_http_args = [uri.host, uri.port]
206:     connection_id = net_http_args.join ':'
207: 
208:     if @proxy_uri then
209:       connection_id << @proxy_connection_id
210:       net_http_args.concat @proxy_args
211:     end
212: 
213:     unless connection = connections[connection_id] then
214:       connections[connection_id] = Net::HTTP.new(*net_http_args)
215:       connection = connections[connection_id]
216:       ssl connection if uri.scheme == 'https'
217:     end
218: 
219:     unless connection.started? then
220:       connection.set_debug_output @debug_output if @debug_output
221:       connection.open_timeout = @open_timeout if @open_timeout
222:       connection.read_timeout = @read_timeout if @read_timeout
223: 
224:       connection.start
225:     end
226: 
227:     connection
228:   rescue Errno::ECONNREFUSED
229:     raise Error, "connection refused: #{connection.address}:#{connection.port}"
230:   rescue Errno::EHOSTDOWN
231:     raise Error, "host down: #{connection.address}:#{connection.port}"
232:   end
error_message(connection) click to toggle source

Returns an error message containing the number of requests performed on this connection

     # File lib/bundler/vendor/net/http/persistent.rb, line 238
238:   def error_message connection
239:     requests =
240:       Thread.current[@request_key][connection.object_id]
241: 
242:     "after #{requests} requests on #{connection.object_id}"
243:   end
escape(str) click to toggle source

URI::escape wrapper

     # File lib/bundler/vendor/net/http/persistent.rb, line 248
248:   def escape str
249:     CGI.escape str if str
250:   end
finish(connection) click to toggle source

Finishes the Net::HTTP connection

     # File lib/bundler/vendor/net/http/persistent.rb, line 255
255:   def finish connection
256:     Thread.current[@request_key].delete connection.object_id
257: 
258:     connection.finish
259:   rescue IOError
260:   end
http_version(uri) click to toggle source

Returns the HTTP protocol version for uri

     # File lib/bundler/vendor/net/http/persistent.rb, line 265
265:   def http_version uri
266:     @http_versions["#{uri.host}:#{uri.port}"]
267:   end
idempotent?(req) click to toggle source

Is req idempotent according to RFC 2616?

     # File lib/bundler/vendor/net/http/persistent.rb, line 272
272:   def idempotent? req
273:     case req
274:     when Net::HTTP::Delete, Net::HTTP::Get, Net::HTTP::Head,
275:          Net::HTTP::Options, Net::HTTP::Put, Net::HTTP::Trace then
276:       true
277:     end
278:   end
normalize_uri(uri) click to toggle source

Adds “http://” to the String uri if it is missing.

     # File lib/bundler/vendor/net/http/persistent.rb, line 283
283:   def normalize_uri uri
284:     (uri =~ /^https?:/) ? uri : "http://#{uri}"
285:   end
proxy_from_env() click to toggle source

Creates a URI for an HTTP proxy server from ENV variables.

If HTTP_PROXY is set a proxy will be returned.

If HTTP_PROXY_USER or HTTP_PROXY_PASS are set the URI is given the indicated user and password unless HTTP_PROXY contains either of these in the URI.

For Windows users lowercase ENV variables are preferred over uppercase ENV variables.

     # File lib/bundler/vendor/net/http/persistent.rb, line 299
299:   def proxy_from_env
300:     env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
301: 
302:     return nil if env_proxy.nil? or env_proxy.empty?
303: 
304:     uri = URI.parse normalize_uri env_proxy
305: 
306:     unless uri.user or uri.password then
307:       uri.user     = escape ENV['http_proxy_user'] || ENV['HTTP_PROXY_USER']
308:       uri.password = escape ENV['http_proxy_pass'] || ENV['HTTP_PROXY_PASS']
309:     end
310: 
311:     uri
312:   end
request(uri, req = nil, &block) click to toggle source

Makes a request on uri. If req is nil a Net::HTTP::Get is performed against uri.

If a block is passed # behaves like Net::HTTP#request (the body of the response will not have been read).

req must be a Net::HTTPRequest subclass (see Net::HTTP for a list).

If there is an error and the request is idempontent according to RFC 2616 it will be retried automatically.

     # File lib/bundler/vendor/net/http/persistent.rb, line 341
341:   def request uri, req = nil, &block
342:     retried      = false
343:     bad_response = false
344: 
345:     req = Net::HTTP::Get.new uri.request_uri unless req
346: 
347:     headers.each do |pair|
348:       req.add_field(*pair)
349:     end
350: 
351:     if uri.user or uri.password
352:       req.basic_auth uri.user, uri.password
353:     end
354: 
355:     req.add_field 'Connection', 'keep-alive'
356:     req.add_field 'Keep-Alive', @keep_alive
357: 
358:     connection = connection_for uri
359:     connection_id = connection.object_id
360: 
361:     begin
362:       Thread.current[@request_key][connection_id] += 1
363:       response = connection.request req, &block
364: 
365:     rescue Net::HTTPBadResponse => e
366:       message = error_message connection
367: 
368:       finish connection
369: 
370:       raise Error, "too many bad responses #{message}" if
371:         bad_response or not idempotent? req
372: 
373:       bad_response = true
374:       retry
375:     rescue IOError, EOFError, Timeout::Error,
376:            Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
377: 
378:       if retried or not idempotent? req
379:         due_to = "(due to #{e.message} - #{e.class})"
380:         message = error_message connection
381: 
382:         finish connection
383: 
384:         raise Error, "too many connection resets #{due_to} #{message}"
385:       end
386: 
387:       reset connection
388: 
389:       retried = true
390:       retry
391:     end
392: 
393:     @http_versions["#{uri.host}:#{uri.port}"] ||= response.http_version
394: 
395:     response
396:   end
reset(connection) click to toggle source

Finishes then restarts the Net::HTTP connection

     # File lib/bundler/vendor/net/http/persistent.rb, line 317
317:   def reset connection
318:     Thread.current[@request_key].delete connection.object_id
319: 
320:     finish connection
321: 
322:     connection.start
323:   rescue Errno::ECONNREFUSED
324:     raise Error, "connection refused: #{connection.address}:#{connection.port}"
325:   rescue Errno::EHOSTDOWN
326:     raise Error, "host down: #{connection.address}:#{connection.port}"
327:   end
shutdown(thread = Thread.current) click to toggle source

Shuts down all connections for thread.

Uses the current thread by default.

If you’ve used Net::HTTP::Persistent across multiple threads you should call this in each thread when you’re done making HTTP requests.

NOTE: Calling shutdown for another thread can be dangerous!

If the thread is still using the connection it may cause an error! It is best to call # in the thread at the appropriate time instead!

     # File lib/bundler/vendor/net/http/persistent.rb, line 411
411:   def shutdown thread = Thread.current
412:     connections = thread[@connection_key]
413: 
414:     connections.each do |_, connection|
415:       begin
416:         connection.finish
417:       rescue IOError
418:       end
419:     end if connections
420: 
421:     thread[@connection_key] = nil
422:     thread[@request_key]    = nil
423:   end
shutdown_in_all_threads() click to toggle source

Shuts down all connections in all threads

NOTE: THIS METHOD IS VERY DANGEROUS!

Do not call this method if other threads are still using their connections! Call # at the appropriate time instead!

Use this method only as a last resort!

     # File lib/bundler/vendor/net/http/persistent.rb, line 435
435:   def shutdown_in_all_threads
436:     Thread.list.each do |thread|
437:       shutdown thread
438:     end
439: 
440:     nil
441:   end
ssl(connection) click to toggle source

Enables SSL on connection

     # File lib/bundler/vendor/net/http/persistent.rb, line 446
446:   def ssl connection
447:     require 'net/https'
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

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.