promptworks/rack-translating_proxy

View on GitHub
lib/rack/translating_proxy.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'rack/proxy'

module Rack
  class TranslatingProxy < Rack::Proxy
    def rewrite_env(env)
      rewrite_request_url env
      rewrite_request_body env
      rewrite_request_query_string env
      rewrite_request_path env

      env
    end

    def rewrite_request_url(env)
      env['HTTP_HOST']       = _target_host.host
      env['SERVER_PORT']     = _target_host.port
      env['rack.url_scheme'] = _target_host.scheme
    end

    def rewrite_request_body(env)
      rewritten_input = rewrite_request_string(io(env['rack.input']).read)

      env['rack.input']     = io(rewritten_input)
      env['CONTENT_LENGTH'] = rewritten_input.size
    end

    def rewrite_request_string(str)
      rewrite_string(
        str, request_mapping, URI.method(:encode_www_form_component)
      )
    end

    def rewrite_request_query_string(env)
      env['QUERY_STRING'] = rewrite_request_string(env['QUERY_STRING'])
    end

    def rewrite_request_path(env)
      env['PATH_INFO']   = rewrite_request_string(env['PATH_INFO'])
      env['REQUEST_URI'] = rewrite_request_string(env['REQUEST_URI'])
    end

    def rewrite_string(string, mapping, transform = proc { |x| x })
      mapping = mapping.map do |source, target|
        [transform[source], transform[target]]
      end

      mapping.each do |source, target|
        string = string.gsub(source, target)
      end

      string
    end

    def io(stringy_thing)
      if stringy_thing.respond_to?(:read)
        stringy_thing
      else
        StringIO.new(stringy_thing)
      end
    end

    def rewrite_response(triplet)
      status, headers, body = triplet
      rewrite_response_location headers
      remove_interfering_response_headers headers
      body = rewrite_response_body(body)
      headers['Content-Length'] = body.size.to_s
      [status, headers, [body]]
    end

    def rewrite_response_location(headers)
      return unless headers['location']

      headers['location'] = headers['location'].map do |location|
        rewrite_string(location, _response_mapping)
      end
    end

    def remove_interfering_response_headers(headers)
      headers.reject! do |key, _|
        %w(status connection transfer-encoding).include?(key)
      end
    end

    def rewrite_response_body(body)
      str = rewrite_string(body.to_s, _response_mapping)
      rewrite_string(str, _response_mapping,
                     URI.method(:encode_www_form_component))
    end

    def request_mapping
      fail 'Not implemented'
    end

    def _request_mappping
      @_request_mappping ||= request_mappping
    end

    def _response_mapping
      @_response_mapping ||= request_mapping.invert
    end

    def _target_host
      @_target_host ||= URI(target_host)
    end

    def target_host
      fail 'Not implemented'
    end
  end
end