Class Stella::Client

  1. lib/stella/client.rb
Parent: Object

Methods

public class

  1. new

public instance

  1. create_http_client
  2. debug
  3. done!
  4. done?
  5. exception
  6. execute
  7. run_sleeper

Included modules

  1. Gibbler::Complex
  2. HTTPClient::Timeout

Constants

SSL_CERT_PATH = File.join(STELLA_LIB_HOME, '..', 'certs', 'stella-master.crt').freeze

Attributes

base_uri [RW]
clientid [R]
created [RW]
index [R]
proxy [RW]

Public class methods

new (opts={})

Options:

  • :timeout (Integer) => 30
  • :ssl_verify_mode (Class) => nil (possible values: OpenSSL::SSL::VERIFY_NONE)
[show source]
# File lib/stella/client.rb, line 34
    def initialize(opts={})
      @index = @@client_index += 1
      @created = Stella.now
      @opts = opts
      @opts[:timeout] ||= 30
      @base_uri, @index = opts[:base_uri] || opts['base_uri'], index
      @proxy = OpenStruct.new
      @done = false
      @session = Session.new @base_uri
      @redirect_count = 0
      @clientid = [@session.object_id, created, index, opts].digest
    end

Public instance methods

create_http_client ()
[show source]
# File lib/stella/client.rb, line 195
    def create_http_client
      http_client = HTTPClient.new(
        :agent_name  => @opts[:agent] || @opts['agent'] || Stella.agent,
        :from        => nil
      )
      #http_client.set_proxy_auth(@proxy.user, @proxy.pass) if @proxy.user
      #http_client.debug_dev = STDOUT if Stella.debug?
      http_client.protocol_version = "HTTP/1.1"
      if @opts[:ssl_verify_mode]
        http_client.ssl_config.verify_mode = @opts[:ssl_verify_mode]
      end
      
      # See: http://ghouston.blogspot.com/2006/03/using-ssl-with-ruby-http-access2.html
      begin 
        http_client.ssl_config.clear_cert_store
        http_client.ssl_config.set_trust_ca SSL_CERT_PATH
      rescue => ex
        Stella.li ex.class, ex.message
        Stella.ld ex.backtrace
      end
      
      http_client.connect_timeout = @opts[:timeout]
      http_client.send_timeout = @opts[:timeout]
      http_client.receive_timeout = @opts[:timeout]
      http_client
    end
debug (msg)
[show source]
# File lib/stella/client.rb, line 191
    def debug(msg)
      Stella.ld " #{clientid.short} #{msg}"
    end
done! ()
[show source]
# File lib/stella/client.rb, line 222
    def done!
      @done = true
    end
done? ()
[show source]
# File lib/stella/client.rb, line 226
    def done?
      @done == true
    end
exception ()
[show source]
# File lib/stella/client.rb, line 47
    def exception 
      @session.exception
    end
execute (usecase, &each_request)
[show source]
# File lib/stella/client.rb, line 51
    def execute usecase, &each_request
      @session.http_client = create_http_client
      tt = Benelux.current_track.timeline
      usecase.requests.each_with_index do |rt,idx|
        begin 
          debug "request start (session: #{@session.object_id})"
          @session.prepare_request usecase, rt 
          
          debug "#{@session.http_method} #{@session.uri} (#{rt.id.short})"
          debug " #{@session.params.inspect}" unless @session.params.empty?
          debug " #{@session.headers.inspect}" unless @session.headers.empty?
          
          stella_id = [clientid, rt.id, @session.uri.to_s, @session.params, @session.headers, idx].digest
          
          Benelux.current_track.add_tags :request   => rt.id
          Benelux.current_track.add_tags :stella_id => stella_id
          
          ## Useful for testing larger large request header
          ## 50.times do |idx|
          ##   headers["X-header-#{idx}"] = (1000 << 1000).to_s
          ## end
          
          # Mis-behaving HTTP servers will fail w/o an Accept header
          @session.headers["Accept"] ||= '*/*'
          
          # if hard_timeout is nil this will do nothing
          timeout(@opts[:hard_timeout], TimeoutError) do
            @session.generate_request stella_id
          end
          res = @session.res
          
          each_request.call(@session) unless each_request.nil?
          
          # Needs to happen before handle response incase it raises an exception
          log = Stella::Log::HTTP.new Stella.now,  
                   @session.http_method, @session.uri, @session.params, res.request.header.dump, 
                   res.request.body.content, res.status, res.header.dump, res.body.content
          
          tt.add_count :requests, 1, :kind => :http
          
          run_sleeper @opts[:wait] unless usecase.requests.size == idx+1
          
          if @session.response_handler?
            @session.handle_response
          elsif res.status >= 400
            raise Stella::HTTPError.new(res.status)
          elsif rt.follow && @session.redirect?
            raise ForcedRedirect, @session.location
          end

          tt.add_message log, :status => res.status, :kind => :http_log, :state => :nominal
          
          @redirect_count = 0
          
        rescue RepeatRequest => ex
          debug " REPEAT REQUEST: #{@session.location}"
          retry
          
        rescue ForcedRedirect => ex  
          # TODO: warn when redirecting from https to http
          debug " FOUND REDIRECT: #{@session.location}"
          if @redirect_count < 10
            @redirect_count += 1
            @session.clear_previous_request
            @session.redirect_uri = ex.location
            retry
          end
        
        rescue Errno::ETIMEDOUT, SocketError, 
               HTTPClient::ConnectTimeoutError, 
               HTTPClient::SendTimeoutError,
               HTTPClient::ReceiveTimeoutError,
               TimeoutError,
               Errno::ECONNRESET => ex
          debug "[#{ex.class}] #{ex.message}"
          log = Stella::Log::HTTP.new Stella.now, @session.http_method, @session.uri, @session.params
          if @session.res 
            log.request_headers = @session.res.request.header.dump if @session.res.request 
            log.request_body = @session.res.request.body.content if @session.res.request 
            log.response_status = @session.res.status
            log.response_headers = @session.res.header.dump if @session.res.content
            log.response_body = @session.res.body.content if @session.res.body
          end
          log.msg = "#{ex.class} (#{@session.http_client.receive_timeout})"
          tt.add_message log, :kind => :http_log, :state => :timeout
          Benelux.current_track.remove_tags :status, :request, :stella_id
          next
          
        rescue StellaError, StellaBehavior => ex
          debug "[#{ex.class}] #{ex.message}"
          log = Stella::Log::HTTP.new Stella.now, @session.http_method, @session.uri, @session.params
          if @session.res 
            log.request_headers = @session.res.request.header.dump if @session.res.request 
            log.request_body = @session.res.request.body.content if @session.res.request 
            log.response_status = @session.res.status
            log.response_headers = @session.res.header.dump if @session.res.content
            log.response_body = @session.res.body.content if @session.res.body
          end
          log.msg = ex.message
          tt.add_message log, :status => log.response_status, :kind => :http_log, :state => :exception
          Benelux.current_track.remove_tags :status, :request, :stella_id
          @session.exception = ex
          break
        
        rescue Errno::ECONNREFUSED => ex
          debug "[#{ex.class}] #{ex.message}"
          log = Stella::Log::HTTP.new Stella.now, @session.http_method, @session.uri, @session.params
          log.msg = "Connection refused"
          tt.add_message log, :status => log.response_status, :kind => :http_log, :state => :exception
          Benelux.current_track.remove_tags :status, :request, :stella_id
          break
        
        rescue OpenSSL::SSL::SSLError => ex
          debug "[#{ex.class}] #{ex.message}"
          log = Stella::Log::HTTP.new Stella.now, @session.http_method, @session.uri, @session.params
          log.msg = ex.message
          tt.add_message log, :status => log.response_status, :kind => :http_log, :state => :exception
          Benelux.current_track.remove_tags :status, :request, :stella_id
          break
          
        rescue => ex
          Stella.le "[#{ex.class}] #{ex.message}", ex.backtrace
          log = Stella::Log::HTTP.new Stella.now, @session.http_method, @session.uri, @session.params
          log.msg = ex.message
          tt.add_message log, :status => log.response_status, :kind => :http_log, :state => :fubar
          Benelux.current_track.remove_tags :status, :request, :stella_id
          break
          
        end
      end
      
    end
run_sleeper (dur)
[show source]
# File lib/stella/client.rb, line 184
    def run_sleeper dur
      return unless dur && dur > 0
      dur = (rand * (dur.last-dur.first) + dur.first) if Range === dur
      debug "sleep: #{dur}"
      sleep dur
    end