Class: PersistentHTTP::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/persistent_http/connection.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Connection

Creates a new HTTP Connection.

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'


138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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
# File 'lib/persistent_http/connection.rb', line 138

def initialize(options={})
  @name            = options[:name]            || 'PeristentHTTP::Connection'
  @ca_file         = options[:ca_file]
  @certificate     = options[:certificate]
  @debug_output    = options[:debug_output]
  @default_path    = options[:default_path]
  @force_retry     = options[:force_retry]
  @headers         = options[:header]          || {}
  @host            = options[:host]
  @keep_alive      = options[:keep_alive]      || 30
  @logger          = options[:logger]
  @port            = options[:port]
  @private_key     = options[:private_key]
  @open_timeout    = options[:open_timeout]
  @read_timeout    = options[:read_timeout]
  @use_ssl         = options[:use_ssl]
  @verify_callback = options[:verify_callback]
  @verify_mode     = options[:verify_mode]
  # Because maybe we want a non-persistent connection and are just using this for the proxy stuff
  @non_persistent  = options[:non_persistent]

  url              = options[:url]
  if url
    url = URI.parse(url) if url.kind_of? String
    @default_path ||= url.request_uri
    @host         ||= url.host
    @port         ||= url.port
    @use_ssl      ||= url.scheme == 'https'
  end

  @port ||= (@use_ssl ? 443 : 80)

  raise 'host not set' unless @host
  @net_http_args = [@host, @port]

  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,
    ]

    @net_http_args.concat @proxy_args
  end

  @name += ':' + @net_http_args.join(':')
  @logger.debug { "#{@name}: Creating connection" } if @logger
  renew
end

Instance Attribute Details

#ca_fileObject

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



34
35
36
# File 'lib/persistent_http/connection.rb', line 34

def ca_file
  @ca_file
end

#certificateObject

This client’s OpenSSL::X509::Certificate



38
39
40
# File 'lib/persistent_http/connection.rb', line 38

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.



45
46
47
# File 'lib/persistent_http/connection.rb', line 45

def debug_output
  @debug_output
end

#default_pathObject

Default path for the request



49
50
51
# File 'lib/persistent_http/connection.rb', line 49

def default_path
  @default_path
end

#force_retryObject

Retry even for non-idempotent (POST) requests.



53
54
55
# File 'lib/persistent_http/connection.rb', line 53

def force_retry
  @force_retry
end

#headersObject

Headers that are added to every request



57
58
59
# File 'lib/persistent_http/connection.rb', line 57

def headers
  @headers
end

#hostObject (readonly)

Host for the Net:HTTP connection



61
62
63
# File 'lib/persistent_http/connection.rb', line 61

def host
  @host
end

#http_versionObject (readonly)

HTTP version to enable version specific features.



65
66
67
# File 'lib/persistent_http/connection.rb', line 65

def http_version
  @http_version
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.



75
76
77
# File 'lib/persistent_http/connection.rb', line 75

def keep_alive
  @keep_alive
end

#loggerObject

Logger for message logging.



79
80
81
# File 'lib/persistent_http/connection.rb', line 79

def logger
  @logger
end

#nameObject (readonly)

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



84
85
86
# File 'lib/persistent_http/connection.rb', line 84

def name
  @name
end

#open_timeoutObject

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



88
89
90
# File 'lib/persistent_http/connection.rb', line 88

def open_timeout
  @open_timeout
end

#portObject (readonly)

Port for the Net:HTTP connection



92
93
94
# File 'lib/persistent_http/connection.rb', line 92

def port
  @port
end

#private_keyObject

This client’s SSL private key



96
97
98
# File 'lib/persistent_http/connection.rb', line 96

def private_key
  @private_key
end

#proxy_uriObject (readonly)

The URL through which requests will be proxied



100
101
102
# File 'lib/persistent_http/connection.rb', line 100

def proxy_uri
  @proxy_uri
end

#read_timeoutObject

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



104
105
106
# File 'lib/persistent_http/connection.rb', line 104

def read_timeout
  @read_timeout
end

#use_sslObject (readonly)

Use ssl if set



108
109
110
# File 'lib/persistent_http/connection.rb', line 108

def use_ssl
  @use_ssl
end

#verify_callbackObject

SSL verification callback. Used when ca_file is set.



112
113
114
# File 'lib/persistent_http/connection.rb', line 112

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.



119
120
121
# File 'lib/persistent_http/connection.rb', line 119

def verify_mode
  @verify_mode
end

Instance Method Details

#finishObject

Finishes the Net::HTTP connection



287
288
289
290
# File 'lib/persistent_http/connection.rb', line 287

def finish
  @connection.finish
rescue IOError
end

#renewObject



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/persistent_http/connection.rb', line 197

def renew
  finish if @connection
  @message_count = 0
  @connection = Net::HTTP.new(*@net_http_args)
  @connection.set_debug_output @debug_output if @debug_output
  @connection.open_timeout = @open_timeout if @open_timeout
  @connection.read_timeout = @read_timeout if @read_timeout

  ssl if @use_ssl

  @connection.start
  @logger.debug { "#{@name} #{@connection}: Connection created" } if @logger
rescue Errno::ECONNREFUSED
  raise Error, "connection refused: #{@connection.address}:#{@connection.port}"
rescue Errno::EHOSTDOWN
  raise Error, "host down: #{@connection.address}:#{@connection.port}"
end

#request(req = nil, options = {}, &block) ⇒ Object

Makes a request per req. If req is nil a Net::HTTP::Get is performed against default_path.

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.



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
278
279
280
281
282
# File 'lib/persistent_http/connection.rb', line 227

def request(req = nil, options = {}, &block)
  retried      = false
  bad_response = false

  req = Net::HTTP::Get.new @default_path unless req

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

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

  begin
    options.each do |key, value|
      @connection.send("#{key}=", value)
    end
    response = @connection.request req, &block
    @http_version ||= response.http_version
    @message_count += 1
    return response

  rescue Timeout::Error => e
    due_to = "(due to #{e.message} - #{e.class})"
    @logger.info "#{@name}: Removing connection #{due_to} #{error_message}" if @logger
    finish
    raise

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

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

#to_sObject



292
293
294
# File 'lib/persistent_http/connection.rb', line 292

def to_s
  @name
end