class RackReverseProxy::RoundTrip

RoundTrip represents one request-response made by rack-reverse-proxy middleware.

Attributes

app[R]
env[R]
global_options[R]
response_builder_klass[R]
rules[R]

Public Class Methods

new(app, env, global_options, rules, response_builder_klass = ResponseBuilder) click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 10
def initialize(app, env, global_options, rules, response_builder_klass = ResponseBuilder)
  @app = app
  @env = env
  @global_options = global_options
  @rules = rules
  @response_builder_klass = response_builder_klass
end

Public Instance Methods

call() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 18
def call
  return app.call(env) if rule.nil?
  return proxy_with_newrelic if new_relic?
  proxy
end

Private Instance Methods

action_name() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 38
def action_name
  "#{action_path}/#{source_request.request_method}"
end
action_path() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 42
def action_path
  # Rack::ReverseProxy/foo/bar#GET
  source_request.path.gsub(%r{/\d+}, "/:id").gsub(%r{^/}, "")
end
ambiguous_match?() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 270
def ambiguous_match?
  matches.length > 1 && global_options[:matching] != :first
end
body?() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 127
def body?
  source_request.body
end
build_response_headers() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 156
def build_response_headers
  ["Transfer-Encoding", "Status"].inject(rack_response_headers) do |acc, header|
    acc.delete(header)
    acc
  end
end
build_target_request() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 76
def build_target_request
  Net::HTTP.const_get(
    source_request.request_method.capitalize
  ).new(uri.request_uri)
end
can_have_body?() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 123
def can_have_body?
  target_request.request_body_permitted?
end
content_type?() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 140
def content_type?
  source_request.content_type
end
find_rule() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 245
def find_rule
  return if matches.empty?
  non_ambiguous_match
  matches.first
end
format_headers(headers) click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 218
def format_headers(headers)
  headers.inject({}) do |acc, (key, val)|
    formated_key = key.split("-").map(&:capitalize).join("-")
    acc[formated_key] = Array(val)
    acc
  end
end
headers() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 255
def headers
  Rack::Proxy.extract_http_request_headers(source_request.env)
end
host_header() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 92
def host_header
  return uri.host if uri.port == uri.default_port
  "#{uri.host}:#{uri.port}"
end
https_redirect() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 56
def https_redirect
  rewrite_uri(uri, source_request)
  uri.scheme = "https"
  [301, { "Location" => uri.to_s }, ""]
end
initialize_http_header() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 104
def initialize_http_header
  target_request.initialize_http_header(target_request_headers)
end
matches() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 259
def matches
  @_matches ||= rules.select do |rule|
    rule.proxy?(path, headers, source_request)
  end
end
need_basic_auth?() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 113
def need_basic_auth?
  options[:username] && options[:password]
end
need_https_redirect?() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 62
def need_https_redirect?
  options[:force_ssl] &&
    options[:replace_response_host] &&
    source_request.scheme == "http"
end
need_replace_location?() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 181
def need_replace_location?
  response_headers["Location"] && options[:replace_response_host]
end
new_relic?() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 28
def new_relic?
  global_options[:newrelic_instrumentation]
end
non_ambiguous_match() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 265
def non_ambiguous_match
  return unless ambiguous_match?
  raise Errors::AmbiguousMatch.new(path, matches)
end
options() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 52
def options
  @_options ||= global_options.dup.merge(rule.options)
end
path() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 251
def path
  @_path ||= source_request.fullpath
end
preserve_encoding() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 87
def preserve_encoding
  return if options[:preserve_encoding]
  target_request_headers.delete("Accept-Encoding")
end
preserve_host() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 82
def preserve_host
  return unless options[:preserve_host]
  target_request_headers["HOST"] = host_header
end
proxy() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 204
def proxy
  return app.call(env) if uri.nil?
  return https_redirect if need_https_redirect?

  setup_request
  setup_response_headers

  transform_response(rack_response)
end
proxy_with_newrelic() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 32
def proxy_with_newrelic
  perform_action_with_newrelic_trace(:name => action_name, :request => source_request) do
    proxy
  end
end
rack_response() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 200
def rack_response
  [target_response.status, response_headers, target_response.body]
end
rack_response_headers() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 163
def rack_response_headers
  Rack::Utils::HeaderHash.new(
    Rack::Proxy.normalize_headers(
      format_headers(target_response.headers)
    )
  )
end
replace_location_header() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 171
def replace_location_header
  return unless need_replace_location?
  rewrite_uri(response_location, source_request)
  response_headers["Location"] = response_location.to_s
end
request_default_port?(req) click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 226
def request_default_port?(req)
  [["http", 80], ["https", 443]].include?([req.scheme, req.port])
end
response_headers() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 152
def response_headers
  @_response_headers ||= build_response_headers
end
response_location() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 177
def response_location
  @_response_location ||= URI(response_headers["Location"])
end
rewrite_uri(uri, original_req) click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 230
def rewrite_uri(uri, original_req)
  uri.scheme = original_req.scheme
  uri.host   = original_req.host
  uri.port   = original_req.port unless request_default_port?(original_req)
end
rule() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 240
def rule
  return @_rule if defined?(@_rule)
  @_rule = find_rule
end
set_basic_auth() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 108
def set_basic_auth
  return unless need_basic_auth?
  target_request.basic_auth(options[:username], options[:password])
end
set_content_length() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 131
def set_content_length
  target_request.content_length = source_request.content_length || 0
end
set_content_type() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 135
def set_content_type
  return unless content_type?
  target_request.content_type = source_request.content_type
end
set_forwarded_headers() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 97
def set_forwarded_headers
  return unless options[:x_forwarded_headers]
  target_request_headers["X-Forwarded-Host"] = source_request.host
  target_request_headers["X-Forwarded-Port"] = source_request.port.to_s
  target_request_headers["X-Forwarded-Proto"] = source_request.scheme
end
setup_body() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 117
def setup_body
  return unless can_have_body? && body?
  source_request.body.rewind
  target_request.body_stream = source_request.body
end
setup_request() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 185
def setup_request
  preserve_host
  preserve_encoding
  set_forwarded_headers
  initialize_http_header
  set_basic_auth
  setup_body
  set_content_length
  set_content_type
end
setup_response_headers() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 196
def setup_response_headers
  replace_location_header
end
source_request() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 236
def source_request
  @_source_request ||= Rack::Request.new(env)
end
target_request() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 68
def target_request
  @_target_request ||= build_target_request
end
target_request_headers() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 72
def target_request_headers
  @_target_request_headers ||= headers
end
target_response() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 144
def target_response
  @_target_response ||= response_builder_klass.new(
    target_request,
    uri,
    options
  ).fetch
end
transform_response(response) click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 214
def transform_response(response)
  rule.transform(path, env, response, uri, headers, source_request)
end
uri() click to toggle source
# File lib/rack_reverse_proxy/roundtrip.rb, line 47
def uri
  return @_uri if defined?(@_uri)
  @_uri = rule.get_uri(path, env, headers, source_request)
end