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
The version of Net::HTTP::Persistent use are using
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.
Maps host:port to an HTTP version. This allows us to enable version specific features.
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.
A name for this connection. Allows you to keep your connections apart from everybody else’s.
HTTPS verify mode. Defaults to OpenSSL::SSL::VERIFY_NONE which ignores certificate problems.
You can use verify_mode to override any default values.
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
Generated with the Darkfish Rdoc Generator 1.1.6.