class Invoker::Power::Balancer

Attributes

connection[RW]
http_parser[RW]
protocol[RW]
session[RW]
upgraded_to[RW]

Public Class Methods

new(connection, protocol) click to toggle source
# File lib/invoker/power/balancer.rb, line 41
def initialize(connection, protocol)
  @connection = connection
  @protocol = protocol
  @http_parser = HttpParser.new(protocol)
  @session = nil
  @upgraded_to = nil
  @buffer = []
end
run(options = {}) click to toggle source
# File lib/invoker/power/balancer.rb, line 27
def self.run(options = {})
  start_http_proxy(InvokerHttpProxy, 'http', options)
  start_http_proxy(InvokerHttpsProxy, 'https', options)
end
start_http_proxy(proxy_class, protocol, options) click to toggle source
# File lib/invoker/power/balancer.rb, line 32
def self.start_http_proxy(proxy_class, protocol, options)
  port = protocol == 'http' ? Invoker.config.http_port : Invoker.config.https_port
  EventMachine.start_server('0.0.0.0', port,
                            proxy_class, options) do |connection|
    balancer = Balancer.new(connection, protocol)
    balancer.install_callbacks
  end
end

Public Instance Methods

append_for_http_parsing(data) click to toggle source
# File lib/invoker/power/balancer.rb, line 94
def append_for_http_parsing(data)
  http_parser << data
rescue HTTP::Parser::Error
  http_parser.reset
  connection.close_connection_after_writing
end
backend_data(backend, data) click to toggle source
# File lib/invoker/power/balancer.rb, line 101
def backend_data(backend, data)
  @backend_data = true

  # check backend data for websockets connection. check for upgrade headers
  # - Upgrade: websocket\r\n
  if data =~ /Upgrade: websocket/
    @upgraded_to = "websocket"
  end

  data
end
complete_message_received(full_message) click to toggle source
# File lib/invoker/power/balancer.rb, line 58
def complete_message_received(full_message)
  connection.relay_to_servers(full_message)
  http_parser.reset
end
frontend_disconnect(backend, name) click to toggle source
# File lib/invoker/power/balancer.rb, line 113
def frontend_disconnect(backend, name)
  http_parser.reset
  unless @backend_data
    return_error_page(503)
  end
  @backend_data = false
  connection.close_connection_after_writing if backend == session
end
headers_received(headers) click to toggle source
# File lib/invoker/power/balancer.rb, line 63
def headers_received(headers)
  if @session
    return
  end
  @session = UUID.generate()
  headers = headers.transform_keys(&:downcase)

  if !headers['host'] || headers['host'].empty?
    return_error_page(400)
    return
  end

  dns_check_response = UrlRewriter.new.select_backend_config(headers['host'])
  if dns_check_response && dns_check_response.port
    connection.server(session, host: dns_check_response.ip, port: dns_check_response.port)
  else
    return_error_page(404)
    http_parser.reset
    connection.close_connection_after_writing
  end
end
install_callbacks() click to toggle source
# File lib/invoker/power/balancer.rb, line 50
def install_callbacks
  http_parser.on_headers_complete { |headers| headers_received(headers) }
  http_parser.on_message_complete { |full_message| complete_message_received(full_message) }
  connection.on_data { |data| upstream_data(data) }
  connection.on_response { |backend, data| backend_data(backend, data) }
  connection.on_finish { |backend, name| frontend_disconnect(backend, name) }
end
upstream_data(data) click to toggle source
# File lib/invoker/power/balancer.rb, line 85
def upstream_data(data)
  if upgraded_to == "websocket"
    data
  else
    append_for_http_parsing(data)
    nil
  end
end

Private Instance Methods

return_error_page(status) click to toggle source
# File lib/invoker/power/balancer.rb, line 124
def return_error_page(status)
  http_response = Invoker::Power::HttpResponse.new()
  http_response.status = status
  http_response['Content-Type'] = "text/html; charset=utf-8"
  http_response.use_file_as_body(File.join(File.dirname(__FILE__), "templates/#{status}.html"))
  connection.send_data(http_response.http_string)
end