class RSence::Broker

Broker sets up Rack and routes requests to the proper request processing instance.

Public Class Methods

call(env) click to toggle source
# File lib/rsence/http/rackup.rb, line 62
def self.call(env)
  request  = Request.new(env)
  response = Response.new
  request_method = request.request_method.downcase
  if request_method == 'get'
    puts "get: #{request.fullpath}" if $DEBUG_MODE
    sleep @@ping_sim if @@ping_sim
    not_found( request, response ) unless @@transporter.servlet( :get, request, response )
  elsif request_method == 'post'
    puts "post: #{request.fullpath}" if $DEBUG_MODE
    sleep @@ping_sim if @@ping_sim
    not_found( request, response ) unless @@transporter.servlet( :post, request, response )
  else
    puts "unsupported method: #{request_method.inspect}"
  end
  response.header['Content-Length'] = response.body.bytesize.to_s unless response.header.has_key?('Content-Length')
  return [response.status, response.header, response.body]
end
new(request,response) click to toggle source
# File lib/rsence/http/broker.rb, line 64
def initialize(request,response)
  @request  = request
  @response = response
end
start( transporter, conf = {:bind_address => '127.0.0.1', :port => '8001', :rack_require => 'mongrel'} ) click to toggle source

Creates the Rack instance and set up itself accordingly.

@param [Transporter] transporter The single {Transporter} instance initialized by {HTTPDaemon} @param [Hash{Symbol => String}] conf Rack initialization settings @option conf [String] :bind_address (‘127.0.0.1’) The TCP/IP address or mask to bind to. @option conf [#to_i] :port (‘8001’) The TCP port to bind to. @option conf [String] :rack_require (‘mongrel’) The Rack handler to use.

# File lib/rsence/http/broker.rb, line 78
def self.start( transporter, conf = {:bind_address => '127.0.0.1', :port => '8001', :rack_require => 'mongrel'} )
  
  host = conf[:bind_address]
  port = conf[:port]
  
  @@transporter = transporter
  latency = ::RSence.config[:http_server][:latency]
  if latency == 0
    @@ping_sim = false
  else
    @@ping_sim = latency/1000.0
  end
  Thread.new do
    Thread.pass
    puts "Testing if #{host}:#{port} responds.." if ::RSence.args[:debug]
    until RSence.argv.test_port( port, host )
      puts "..#{host}:#{port} doesn't respond yet.." if ::RSence.args[:debug]
      sleep 0.2
    end
    puts "..#{host}:#{port} responds!" if ::RSence.args[:debug]
    if host == '0.0.0.0' and Socket.respond_to?(:ip_address_list)
      puts "RSence is online and responds on the addresses:"
      Socket.ip_address_list.each do |if_addr|
        if RSence.argv.test_port( port, if_addr.ip_address )
          puts "  http://#{if_addr.ip_address}:#{port}#{::RSence.config[:base_url]}"
        end
      end
    else
      puts "RSence is online on the address http://#{host}:#{port}#{::RSence.config[:base_url]}"
    end
    @@transporter.online = true
  end
  
  require 'rack'
  
  # Loads the selected web-server (default is 'mongrel')
  rack_require = conf[:rack_require]
  puts conf.inspect if RSence.args[:debug]

  require rack_require
  require 'rack/handler/puma.rb' if rack_require == 'puma'
  
  # Selects the handler for Rack
  handler = {
    'webrick'  => lambda { Rack::Handler::WEBrick  },
    'thin'     => lambda { Rack::Handler::Thin     },
    'mongrel'  => lambda { Rack::Handler::Mongrel  },
    'puma'     => lambda { Rack::Handler::Puma     }
  }[rack_require].call
  handler.run( self.new, {
    :Host => host, :Port => port
  }.merge( conf[:handler_options] ) )
end
stop() click to toggle source
# File lib/rsence/http/rackup.rb, line 57
def self.stop
  @@transporter.plugins.shutdown
  @@transporter.sessions.shutdown
end

Public Instance Methods

call( env ) click to toggle source

This method is called from Rack. @param [Hash] env is the Rack environment. @return [Array(Number, Hash, Array)] Rack-style response status, header, body

# File lib/rsence/http/broker.rb, line 27
def call( env )
  sleep @@ping_sim if @@ping_sim
  unless @@transporter.online?
    puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} -- Server busy."
    headers = {
      'Retry-After' => '2',
      'Content-Type' => 'text/plain',
      'Refresh' => "2; #{env['REQUEST_URI']}",
      'Content-Length' => '4'
    }
    return [ 503, headers, ['BUSY'] ]
  end
  request  = Request.new(env)
  response = Response.new
  request_method = request.request_method.downcase
  dispatcher = dispatcher_class.new( request, response )
  if dispatcher.respond_to?( request_method )
    begin
      dispatcher.send( request_method )
    rescue => e
      dispatcher.server_error( e )
    end
  else
    dispatcher.not_implemented( request.request_method )
  end
  response_body = response.body
  response.header['Content-Length'] = response.body_bytes unless response.header.has_key?('Content-Length')
  return [response.status, response.header, response_body]
end
connect() click to toggle source

Routes CONNECT requests to {Transporter#servlet}

# File lib/rsence/http/broker.rb, line 231
def connect
  puts "connect: #{@request.fullpath}" if RSence.args[:verbose]
  not_allowed('CONNECT') unless @@transporter.servlet( :connect, @request, @response )
end
delete() click to toggle source

Routes DELETE requests to {Transporter#servlet}

# File lib/rsence/http/broker.rb, line 219
def delete
  puts "delete: #{@request.fullpath}" if RSence.args[:verbose]
  not_allowed('DELETE') unless @@transporter.servlet( :delete, @request, @response )
end
dispatcher_class() click to toggle source

Returns a dynamically created “REST Dispatcher” kind of class that has request and response as instance variables and the rest of the Broker class as the superclass. It calls the method according to the http method. Called from {#call} Broker currently implements only the {#get} and {#post} methods. @return [Broker] An instance of Broker with a {Request} instance as +@request+ and a {Response} instance as +@response+

# File lib/rsence/http/broker.rb, line 62
def dispatcher_class
  @dispatcher ||= Class.new(self.class) do
    def initialize(request,response)
      @request  = request
      @response = response
    end
  end
end
get() click to toggle source

Routes GET requests to {Transporter#servlet}

# File lib/rsence/http/broker.rb, line 148
def get
  puts "get: #{@request.fullpath}" if RSence.args[:verbose]
  not_found unless @@transporter.servlet( :get, @request, @response )
end
head() click to toggle source

Routes HEAD requests to {Transporter#servlet} Uses GET and removes the response body, if nothing matches HEAD directly.

# File lib/rsence/http/broker.rb, line 155
def head
  puts "head: #{@request.fullpath}" if RSence.args[:verbose]
  return if @@transporter.servlet( :head, @request, @response )
  if @@transporter.servlet( :get, @request, @response )
    @response.body = ''
  else
    not_found
  end
end
not_allowed( method_name ) click to toggle source

Generic 405 (method not allowed) handler.

# File lib/rsence/http/broker.rb, line 166
def not_allowed( method_name )
  @response.status = 405
  body_txt = "Error 405: The method #{method_name} is not allowed on #{@request.fullpath}.\r\n"
  @response['Content-Type'] = 'text/plain; charset=UTF-8'
  @response.body = body_txt
end
not_found() click to toggle source

Generic 404 error handler. Just sets up response status, headers, body as a small “Page Not Found” html page

# File lib/rsence/http/broker.rb, line 133
def not_found
  puts "/404: #{@request.fullpath.inspect}" if RSence.args[:verbose]
  @response.status = 404
  err404 = "<html><head><title>404 - Page Not Found</title></head><body>404 - Page &quot;#{@request.fullpath}&quot; Not Found</body></html>"
  @response['Content-Type'] = 'text/html; charset=UTF-8'
  @response.body = err404
end
not_implemented( method_name ) click to toggle source

Generic 501 (method not implemented) handler.

# File lib/rsence/http/broker.rb, line 174
def not_implemented( method_name )
  @response.status = 501
  body_txt = "Error 501: The method #{method_name} is not implemented on #{@request.fullpath}.\r\n"
  @response['Content-Type'] = 'text/plain; charset=UTF-8'
  @response.body = body_txt
end
options() click to toggle source

Routes OPTIONS requests to {Transporter#servlet}

# File lib/rsence/http/broker.rb, line 207
def options
  puts "options: #{@request.fullpath}" if RSence.args[:verbose]
  not_allowed('OPTIONS') unless @@transporter.servlet( :options, @request, @response )
end
post() click to toggle source

Routes POST requests to {Transporter#servlet}

# File lib/rsence/http/broker.rb, line 142
def post
  puts "post: #{@request.fullpath}" if RSence.args[:verbose]
  not_found unless @@transporter.servlet( :post, @request, @response )
end
put() click to toggle source

Routes PUT requests to {Transporter#servlet}

# File lib/rsence/http/broker.rb, line 213
def put
  puts "put: #{@request.fullpath}" if RSence.args[:verbose]
  not_allowed('PUT') unless @@transporter.servlet( :put, @request, @response )
end
server_error( e, custom_name='Broker Exception' ) click to toggle source

Generic 500 (server error) handler.

# File lib/rsence/http/broker.rb, line 182
def server_error( e, custom_name='Broker Exception' )
  @response.status = 500
  exception_detail = [
    custom_name,
    "Time: #{Time.now.to_s}",
    "#{'-='*39}-",
    "#{e.class}: #{e.to_s}",
    "\t#{e.backtrace.join("\r\n\t")}",
    "#{'-='*39}-",
    "Request method: #{@request.request_method}",
    "Request path: #{@request.fullpath}",
    "Request headers: #{@request.header.inspect}",
    "#{'-='*39}-\r\n\r\n"
  ].join("\r\n")
  $stderr.puts exception_detail
  if RSence.args[:debug]
    body_txt = "Error 500: "+ exception_detail
  else
    body_txt = "Error 500: General server error.\r\n"
  end
  @response['Content-Type'] = 'text/plain; charset=UTF-8'
  @response.body = body_txt
end
trace() click to toggle source

Routes TRACE requests to {Transporter#servlet}

# File lib/rsence/http/broker.rb, line 225
def trace
  puts "trace: #{@request.fullpath}" if RSence.args[:verbose]
  not_allowed('TRACE') unless @@transporter.servlet( :trace, @request, @response )
end