class HTTPClient::SessionManager

Manages sessions for a HTTPClient instance.

Attributes

agent_name[RW]

Name of this client. Used for 'User-Agent' header in HTTP request.

chunk_size[RW]

Chunk size for chunked request

connect_retry[RW]

Maximum retry count. 0 for infinite.

connect_timeout[RW]
debug_dev[RW]

Device for dumping log for debugging

from[RW]

Owner of this client. Used for 'From' header in HTTP request.

keep_alive_timeout[RW]
protocol_retry_count[RW]
protocol_version[RW]

Requested protocol version

read_block_size[RW]
receive_timeout[RW]
send_timeout[RW]
socket_local[RW]

Local address to bind local side of the socket to

socket_sync[RW]

Boolean value for Socket#sync

ssl_config[RW]
strict_response_size_check[RW]

Raise BadResponseError if response size does not match with Content-Length header in response.

tcp_keepalive[RW]

Boolean value to send TCP keepalive packets; no timing settings exist at present

test_loopback_http_response[R]
transparent_gzip_decompression[RW]

Public Class Methods

new(client) click to toggle source
# File lib/httpclient/session.rb, line 132
def initialize(client)
  @client = client
  @proxy = client.proxy

  @agent_name = nil
  @from = nil

  @protocol_version = nil
  @debug_dev = client.debug_dev
  @socket_sync = true
  @tcp_keepalive = false
  @chunk_size = ::HTTP::Message::Body::DEFAULT_CHUNK_SIZE

  @connect_timeout = 60
  @connect_retry = 1
  @send_timeout = 120
  @receive_timeout = 60        # For each read_block_size bytes
  @keep_alive_timeout = 15     # '15' is from Apache 2 default
  @read_block_size = 1024 * 16 # follows net/http change in 1.8.7
  @protocol_retry_count = 5

  @ssl_config = nil
  @test_loopback_http_response = []

  @transparent_gzip_decompression = false
  @strict_response_size_check = false
  @socket_local = Site.new

  @sess_pool = {}
  @sess_pool_mutex = Mutex.new
  @sess_pool_last_checked = Time.now
end

Public Instance Methods

keep(sess) click to toggle source

assert: sess.last_used must not be nil

# File lib/httpclient/session.rb, line 195
def keep(sess)
  add_cached_session(sess)
end
proxy=(proxy) click to toggle source
# File lib/httpclient/session.rb, line 165
def proxy=(proxy)
  if proxy.nil?
    @proxy = nil
  else
    @proxy = Site.new(proxy)
  end
end
query(req, via_proxy) click to toggle source
# File lib/httpclient/session.rb, line 173
def query(req, via_proxy)
  req.http_body.chunk_size = @chunk_size if req.http_body
  sess = get_session(req, via_proxy)
  begin
    sess.query(req)
  rescue
    sess.close
    raise
  end
  sess
end
reset(uri) click to toggle source
# File lib/httpclient/session.rb, line 185
def reset(uri)
  site = Site.new(uri)
  close(site)
end
reset_all() click to toggle source
# File lib/httpclient/session.rb, line 190
def reset_all
  close_all
end

Private Instance Methods

add_cached_session(sess) click to toggle source
# File lib/httpclient/session.rb, line 298
def add_cached_session(sess)
  @sess_pool_mutex.synchronize do
    (@sess_pool[sess.dest] ||= []).unshift(sess)
  end
end
close(dest) click to toggle source

This method might not work as you expected…

# File lib/httpclient/session.rb, line 251
def close(dest)
  if cached = get_cached_session(Site.new(dest))
    cached.close
    true
  else
    false
  end
end
close_all() click to toggle source
# File lib/httpclient/session.rb, line 239
def close_all
  @sess_pool_mutex.synchronize do
    @sess_pool.each do |site, pool|
      pool.each do |sess|
        sess.close
      end
    end
  end
  @sess_pool.clear
end
get_cached_session(site) click to toggle source
# File lib/httpclient/session.rb, line 260
def get_cached_session(site)
  if Thread.current[:HTTPClient_AcquireNewConnection]
    return nil
  end
  @sess_pool_mutex.synchronize do
    now = Time.now
    if now > @sess_pool_last_checked + @keep_alive_timeout
      scrub_cached_session(now)
      @sess_pool_last_checked = now
    end
    if pool = @sess_pool[site]
      pool.each_with_index do |sess, idx|
        if valid_session?(sess, now)
          return pool.slice!(idx)
        end
      end
    end
  end
  nil
end
get_session(req, via_proxy = false) click to toggle source

TODO: create PR for webmock's httpclient adapter to use get_session instead of open so that we can remove duplicated Site creation for each session.

# File lib/httpclient/session.rb, line 204
def get_session(req, via_proxy = false)
  uri = req.header.request_uri
  if uri.scheme.nil?
    raise ArgumentError.new("Request URI must have schema. Possibly add 'http://' to the request URI?")
  end
  site = Site.new(uri)
  if cached = get_cached_session(site)
    cached
  else
    open(uri, via_proxy)
  end
end
open(uri, via_proxy = false) click to toggle source
# File lib/httpclient/session.rb, line 217
def open(uri, via_proxy = false)
  site = Site.new(uri)
  sess = Session.new(@client, site, @agent_name, @from)
  sess.proxy = via_proxy ? @proxy : nil
  sess.socket_sync = @socket_sync
  sess.tcp_keepalive = @tcp_keepalive
  sess.requested_version = @protocol_version if @protocol_version
  sess.connect_timeout = @connect_timeout
  sess.connect_retry = @connect_retry
  sess.send_timeout = @send_timeout
  sess.receive_timeout = @receive_timeout
  sess.read_block_size = @read_block_size
  sess.protocol_retry_count = @protocol_retry_count
  sess.ssl_config = @ssl_config
  sess.debug_dev = @debug_dev
  sess.strict_response_size_check = @strict_response_size_check
  sess.socket_local = @socket_local
  sess.test_loopback_http_response = @test_loopback_http_response
  sess.transparent_gzip_decompression = @transparent_gzip_decompression
  sess
end
scrub_cached_session(now) click to toggle source
# File lib/httpclient/session.rb, line 281
def scrub_cached_session(now)
  @sess_pool.each do |site, pool|
    pool.replace(pool.select { |sess|
      if valid_session?(sess, now)
        true
      else
        sess.close # close & remove from the pool
        false
      end
    })
  end
end
valid_session?(sess, now) click to toggle source
# File lib/httpclient/session.rb, line 294
def valid_session?(sess, now)
  (now <= sess.last_used + @keep_alive_timeout)
end