class Rack::DynamicReverseProxy

Public Class Methods

new(app = nil, &block) click to toggle source
# File lib/rack/dynamic_reverse_proxy.rb, line 9
def initialize(app = nil, &block)
  @app = app || lambda {|env| [404, [], []] }
  @matchers = []
  @rules = []
  @global_options = {
    preserve_host:         true,
    x_forwarded_host:      true,
    matching:              :all,
    replace_response_host: false
  }
  instance_eval &block if block_given?
end

Public Instance Methods

call(env) click to toggle source
# File lib/rack/dynamic_reverse_proxy.rb, line 22
def call(env)
  rackreq = Rack::Request.new(env)
  rule = get_rule(rackreq)
  # return @app.call(env) if matcher.nil?
  return @app.call(env) if rule.nil?

  # proxy(env, rackreq, matcher)
  proxy(env, rackreq, rule)
end

Private Instance Methods

extract_http_request_headers(env) click to toggle source
# File lib/rack/dynamic_reverse_proxy.rb, line 90
def extract_http_request_headers(env)
  headers = env.reject do |k, v|
    !(/^HTTP_[A-Z_]+$/ === k) || v.nil?
  end.map do |k, v|
    [reconstruct_header_name(k), v]
  end.inject(Utils::HeaderHash.new) do |hash, k_v|
    k, v = k_v
    hash[k] = v
    hash
  end

  x_forwarded_for = (headers["X-Forwarded-For"].to_s.split(/, +/) << env["REMOTE_ADDR"]).join(", ")

  headers.merge!("X-Forwarded-For" =>  x_forwarded_for)
end
get_rule(rackreq) click to toggle source
# File lib/rack/dynamic_reverse_proxy.rb, line 110
def get_rule rackreq
  rules = @rules.select do |rule|
    rule.match? rackreq
  end

  if rules.length < 1
    nil
  else
    rules.first
  end
end
proxy(env, source_request, matcher) click to toggle source
# File lib/rack/dynamic_reverse_proxy.rb, line 34
def proxy(env, source_request, matcher)
  # uri = matcher.get_uri(source_request.fullpath, env)
  uri = matcher.get_uri
  return @app.call(env) if uri.nil?

  # options = @global_options.dup.merge(matcher.options)
  options = @global_options.dup

  # Initialize request
  target_request = Net::HTTP.const_get(source_request.request_method.capitalize).new(uri.request_uri)

  # Setup headers
  target_request_headers = extract_http_request_headers(source_request.env)

  if options[:preserve_host]
    target_request_headers['HOST'] = "#{uri.host}:#{uri.port}"
  end

  if options[:x_forwarded_host]
    target_request_headers['X-Forwarded-Host'] = source_request.host
    target_request_headers['X-Forwarded-Port'] = "#{source_request.port}"
  end

  target_request.initialize_http_header(target_request_headers)

  # Basic auth
  target_request.basic_auth options[:username], options[:password] if options[:username] and options[:password]

  # Setup body
  if target_request.request_body_permitted? && source_request.body
    source_request.body.rewind
    target_request.body_stream  = source_request.body
  end

  target_request.content_length = source_request.content_length || 0
  target_request.content_type   = source_request.content_type if source_request.content_type

  # Create a streaming response (the actual network communication is deferred, a.k.a. streamed)
  target_response = HttpStreamingResponse.new(target_request, uri.host, uri.port)

  target_response.use_ssl = "https" == uri.scheme

  # Let rack set the transfer-encoding header
  response_headers = target_response.headers
  response_headers.delete('transfer-encoding')

  # Replace the location header with the proxy domain
  if response_headers['location'] && options[:replace_response_host]
    response_location = URI(response_headers['location'][0])
    response_location.host = source_request.host
    response_headers['location'] = response_location.to_s
  end

  [target_response.status, response_headers, target_response.body]
end
reconstruct_header_name(name) click to toggle source
# File lib/rack/dynamic_reverse_proxy.rb, line 106
def reconstruct_header_name(name)
  name.sub(/^HTTP_/, "").gsub("_", "-")
end
reverse_proxy_options(options) click to toggle source
# File lib/rack/dynamic_reverse_proxy.rb, line 122
def reverse_proxy_options options
  @global_options = options
end
reverse_proxy_rule(rule = nil, &block) click to toggle source
# File lib/rack/dynamic_reverse_proxy.rb, line 126
def reverse_proxy_rule rule = nil, &block
  if block_given?
    @rules << ReverseProxyRule.new(block)
  else
    @rules << ReverseProxyRule.new(rule)
  end
end