module Scrivito class ConnectionManager SOCKET_ERRORS = [ EOFError, Errno::ECONNABORTED, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EINVAL, Errno::EPIPE, Errno::ETIMEDOUT, IOError, SocketError, Timeout::Error, ].freeze DEFAULT_TIMEOUT = 10.freeze attr_reader :uri class << self def instance @instance ||= new(Configuration.endpoint_uri) end # For test purpose only. def reset_instance! @instance = nil end end def initialize(uri) @uri = uri end def request(request, timeout=DEFAULT_TIMEOUT) request['User-Agent'] = user_agent ensure_started(timeout) begin connection.request(request) rescue *SOCKET_ERRORS => e ensure_finished raise NetworkError.from_socket_error(e) end end private attr_accessor :connection def ensure_started(timeout) if @connection && @connection.started? configure_timeout(@connection, timeout) else conn = Net::HTTP.new(uri.host, uri.port) if uri.scheme == 'https' conn.use_ssl = true conn.verify_mode = OpenSSL::SSL::VERIFY_PEER conn.ca_file = Scrivito::Configuration.ca_file end configure_timeout(conn, timeout) retry_twice_on_socket_error do conn.start end @connection = conn end end def ensure_finished @connection.finish if @connection && @connection.started? @connection = nil end def retry_twice_on_socket_error attempt = 0 begin yield rescue *SOCKET_ERRORS => e raise NetworkError.from_socket_error(e) if attempt == 2 attempt += 1 retry end end def configure_timeout(connection, timeout) connection.open_timeout = timeout connection.read_timeout = timeout connection.ssl_timeout = timeout end def user_agent @user_agent ||= "#{GemInfo.name}-#{GemInfo.version}" end end end