Manages sessions for a HTTPClient instance.
Name of this client. Used for 'User-Agent' header in HTTP request.
Chunk size for chunked request
Maximum retry count. 0 for infinite.
Device for dumping log for debugging
Owner of this client. Used for 'From' header in HTTP request.
Requested protocol version
Local address to bind local side of the socket to
Boolean value for Socket#sync
# File lib/httpclient/session.rb, line 121 def initialize(client) @client = client @proxy = client.proxy @agent_name = nil @from = nil @protocol_version = nil @debug_dev = client.debug_dev @socket_sync = true @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 @socket_local = Site.new @sess_pool = {} @sess_pool_mutex = Mutex.new @sess_pool_last_checked = Time.now end
# File lib/httpclient/session.rb, line 186 def invalidate(site) @sess_pool_mutex.synchronize do if pool = @sess_pool[site] pool.each do |sess| sess.invalidate end end end end
assert: sess.last_used must not be nil
# File lib/httpclient/session.rb, line 182 def keep(sess) add_cached_session(sess) end
# File lib/httpclient/session.rb, line 152 def proxy=(proxy) if proxy.nil? @proxy = nil else @proxy = Site.new(proxy) end end
# File lib/httpclient/session.rb, line 160 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
# File lib/httpclient/session.rb, line 172 def reset(uri) site = Site.new(uri) close(site) end
# File lib/httpclient/session.rb, line 177 def reset_all close_all end
# File lib/httpclient/session.rb, line 290 def add_cached_session(sess) @sess_pool_mutex.synchronize do (@sess_pool[sess.dest] ||= []).unshift(sess) end end
This method might not work as you expected…
# File lib/httpclient/session.rb, line 246 def close(dest) if cached = get_cached_session(Site.new(dest)) cached.close true else false end end
# File lib/httpclient/session.rb, line 234 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
# File lib/httpclient/session.rb, line 255 def get_cached_session(site) @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
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 201 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
# File lib/httpclient/session.rb, line 214 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.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.socket_local = @socket_local sess.test_loopback_http_response = @test_loopback_http_response sess.transparent_gzip_decompression = @transparent_gzip_decompression sess end
# File lib/httpclient/session.rb, line 273 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
# File lib/httpclient/session.rb, line 286 def valid_session?(sess, now) !sess.invalidated? and (now <= sess.last_used + @keep_alive_timeout) end