class HTTPClient::SessionManager
Manages sessions for a HTTPClient instance.
def add_cached_session(sess)
def add_cached_session(sess) @sess_pool_mutex.synchronize do (@sess_pool[sess.dest] ||= []).unshift(sess) end end
def close(dest)
def close(dest) if cached = get_cached_session(Site.new(dest)) cached.close true else false end end
def close_all
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
def get_cached_session(site)
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
def get_session(req, via_proxy = false)
instead of open so that we can remove duplicated Site creation for
TODO: create PR for webmock's httpclient adapter to use get_session
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
def initialize(client)
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
def keep(sess)
def keep(sess) add_cached_session(sess) end
def open(uri, via_proxy = false)
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
def proxy=(proxy)
def proxy=(proxy) if proxy.nil? @proxy = nil else @proxy = Site.new(proxy) end end
def query(req, via_proxy)
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
def reset(uri)
def reset(uri) site = Site.new(uri) close(site) end
def reset_all
def reset_all close_all end
def scrub_cached_session(now)
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
def valid_session?(sess, now)
def valid_session?(sess, now) (now <= sess.last_used + @keep_alive_timeout) end