Class: Net::HTTP::Persistent

Inherits:
Object
  • Object
show all
Defined in:
lib/net/http/persistent.rb

Overview

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 which will be checked out of a pool.

You can shut down the HTTP connections when done by calling #shutdown. 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

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =

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

'1.0.0'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Persistent

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'


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/net/http/persistent.rb', line 164

def initialize(options={})
  @name = options[:name] || 'Net::HTTP::Persistent'
  proxy = options[:proxy]

  @proxy_uri = case proxy
               when :ENV      then proxy_from_env
               when URI::HTTP then proxy
               when nil       then # ignore
               else raise ArgumentError, 'proxy must be :ENV or a URI::HTTP'
               end

  if @proxy_uri then
    @proxy_args = [
      @proxy_uri.host,
      @proxy_uri.port,
      @proxy_uri.user,
      @proxy_uri.password,
    ]

    @proxy_connection_id = [nil, *@proxy_args].join ':'
  end

  @ca_file         = options[:ca_file]
  @certificate     = options[:certificate]
  @debug_output    = options[:debug_output]
  @force_retry     = options[:force_retry]
  @headers         = options[:header]          || {}
  @http_versions   = {}
  @keep_alive      = options[:keep_alive]      || 30
  @logger          = options[:logger]
  @open_timeout    = options[:open_timeout]
  @pool_size       = options[:pool_size]       || 1
  @private_key     = options[:private_key]
  @read_timeout    = options[:read_timeout]
  @verify_callback = options[:verify_callback]
  @verify_mode     = options[:verify_mode]
  @warn_timeout    = options[:warn_timeout]    || 0.5
  
  # Hash containing connection pools based on key of host:port
  @pool_hash = {}
  
  # Hash containing the request counts based on the connection
  @count_hash = Hash.new(0)
end

Instance Attribute Details

#ca_fileObject

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



50
51
52
# File 'lib/net/http/persistent.rb', line 50

def ca_file
  @ca_file
end

#certificateObject

This client’s OpenSSL::X509::Certificate



55
56
57
# File 'lib/net/http/persistent.rb', line 55

def certificate
  @certificate
end

#debug_outputObject

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.



63
64
65
# File 'lib/net/http/persistent.rb', line 63

def debug_output
  @debug_output
end

#force_retryObject

Retry even for non-idempotent (POST) requests.



68
69
70
# File 'lib/net/http/persistent.rb', line 68

def force_retry
  @force_retry
end

#headersObject

Headers that are added to every request



73
74
75
# File 'lib/net/http/persistent.rb', line 73

def headers
  @headers
end

#http_versionsObject (readonly)

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



79
80
81
# File 'lib/net/http/persistent.rb', line 79

def http_versions
  @http_versions
end

#keep_aliveObject

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.



90
91
92
# File 'lib/net/http/persistent.rb', line 90

def keep_alive
  @keep_alive
end

#loggerObject

Logger for message logging.



95
96
97
# File 'lib/net/http/persistent.rb', line 95

def logger
  @logger
end

#nameObject (readonly)

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



101
102
103
# File 'lib/net/http/persistent.rb', line 101

def name
  @name
end

#open_timeoutObject

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



106
107
108
# File 'lib/net/http/persistent.rb', line 106

def open_timeout
  @open_timeout
end

#pool_sizeObject (readonly)

The maximum size of the connection pool



111
112
113
# File 'lib/net/http/persistent.rb', line 111

def pool_size
  @pool_size
end

#private_keyObject

This client’s SSL private key



116
117
118
# File 'lib/net/http/persistent.rb', line 116

def private_key
  @private_key
end

#proxy_uriObject (readonly)

The URL through which requests will be proxied



121
122
123
# File 'lib/net/http/persistent.rb', line 121

def proxy_uri
  @proxy_uri
end

#read_timeoutObject

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



126
127
128
# File 'lib/net/http/persistent.rb', line 126

def read_timeout
  @read_timeout
end

#verify_callbackObject

SSL verification callback. Used when ca_file is set.



131
132
133
# File 'lib/net/http/persistent.rb', line 131

def verify_callback
  @verify_callback
end

#verify_modeObject

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

You can use verify_mode to override any default values.



139
140
141
# File 'lib/net/http/persistent.rb', line 139

def verify_mode
  @verify_mode
end

#warn_timeoutObject

The threshold in seconds for checking out a connection at which a warning will be logged via the logger



145
146
147
# File 'lib/net/http/persistent.rb', line 145

def warn_timeout
  @warn_timeout
end

Instance Method Details

#http_version(uri) ⇒ Object

Returns the HTTP protocol version for uri



282
283
284
# File 'lib/net/http/persistent.rb', line 282

def http_version uri
  @http_versions["#{uri.host}:#{uri.port}"]
end

#request(uri, req = nil, &block) ⇒ Object

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

If a block is passed #request 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.



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/net/http/persistent.rb', line 221

def request uri, req = nil, &block
  retried      = false
  bad_response = false

  req = Net::HTTP::Get.new uri.request_uri unless req

  headers.each do |pair|
    req.add_field(*pair)
  end

  req.add_field 'Connection', 'keep-alive'
  req.add_field 'Keep-Alive', @keep_alive

  pool = pool_for uri
  pool.with_connection do |connection|
    begin
      count = @count_hash[connection.object_id] += 1
      response = connection.request req, &block
      @http_versions["#{uri.host}:#{uri.port}"] ||= response.http_version
      return response

    rescue  Timeout::Error => e
      due_to = "(due to #{e.message} - #{e.class})"
      message = error_message connection
      @logger.info "#{name}: Removing connection #{due_to} #{message}" if @logger
      remove pool, connection
      raise
      
    rescue Net::HTTPBadResponse => e
      message = error_message connection
      if bad_response or not (idempotent? req or @force_retry)
        @logger.info "#{name}: Removing connection because of too many bad responses #{message}" if @logger
        remove pool, connection
        raise Error, "too many bad responses #{message}"
      else
        bad_response = true
        @logger.info "#{name}: Renewing connection because of bad response #{message}" if @logger
        connection = renew pool, connection
        retry
      end

    rescue IOError, EOFError, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
      due_to = "(due to #{e.message} - #{e.class})"
      message = error_message connection
      if retried or not (idempotent? req or @force_retry)
        @logger.info "#{name}: Removing connection #{due_to} #{message}" if @logger
        remove pool, connection
        raise Error, "too many connection resets #{due_to} #{message}"
      else
        retried = true
        @logger.info "#{name}: Renewing connection #{due_to} #{message}" if @logger
        connection = renew pool, connection
        retry
      end
    end
  end
end

#shutdownObject

Shuts down all connections.



289
290
291
292
293
# File 'lib/net/http/persistent.rb', line 289

def shutdown
  raise 'Shutdown not implemented'
  # TBD - need to think about this one
  @count_hash = nil
end