Add skeleton
This commit is contained in:
parent
5ebb5e1a1d
commit
0dd5aa6a31
|
@ -0,0 +1,80 @@
|
||||||
|
GEM
|
||||||
|
remote: http://rubygems.org/
|
||||||
|
specs:
|
||||||
|
activesupport (4.2.1)
|
||||||
|
i18n (~> 0.7)
|
||||||
|
json (~> 1.7, >= 1.7.7)
|
||||||
|
minitest (~> 5.1)
|
||||||
|
thread_safe (~> 0.3, >= 0.3.4)
|
||||||
|
tzinfo (~> 1.1)
|
||||||
|
addressable (2.3.8)
|
||||||
|
builder (3.2.2)
|
||||||
|
descendants_tracker (0.0.4)
|
||||||
|
thread_safe (~> 0.3, >= 0.3.1)
|
||||||
|
docile (1.1.5)
|
||||||
|
faraday (0.9.1)
|
||||||
|
multipart-post (>= 1.2, < 3)
|
||||||
|
git (1.2.9.1)
|
||||||
|
github_api (0.12.3)
|
||||||
|
addressable (~> 2.3)
|
||||||
|
descendants_tracker (~> 0.0.4)
|
||||||
|
faraday (~> 0.8, < 0.10)
|
||||||
|
hashie (>= 3.3)
|
||||||
|
multi_json (>= 1.7.5, < 2.0)
|
||||||
|
nokogiri (~> 1.6.3)
|
||||||
|
oauth2
|
||||||
|
hashie (3.4.2)
|
||||||
|
highline (1.7.2)
|
||||||
|
i18n (0.7.0)
|
||||||
|
jeweler (2.0.1)
|
||||||
|
builder
|
||||||
|
bundler (>= 1.0)
|
||||||
|
git (>= 1.2.5)
|
||||||
|
github_api
|
||||||
|
highline (>= 1.6.15)
|
||||||
|
nokogiri (>= 1.5.10)
|
||||||
|
rake
|
||||||
|
rdoc
|
||||||
|
json (1.8.3)
|
||||||
|
jwt (1.5.0)
|
||||||
|
mini_portile (0.6.2)
|
||||||
|
minitest (5.7.0)
|
||||||
|
multi_json (1.11.0)
|
||||||
|
multi_xml (0.5.5)
|
||||||
|
multipart-post (2.0.0)
|
||||||
|
nokogiri (1.6.6.2)
|
||||||
|
mini_portile (~> 0.6.0)
|
||||||
|
oauth2 (1.0.0)
|
||||||
|
faraday (>= 0.8, < 0.10)
|
||||||
|
jwt (~> 1.0)
|
||||||
|
multi_json (~> 1.3)
|
||||||
|
multi_xml (~> 0.5)
|
||||||
|
rack (~> 1.2)
|
||||||
|
rack (1.6.1)
|
||||||
|
rake (10.4.2)
|
||||||
|
rdoc (3.12.2)
|
||||||
|
json (~> 1.4)
|
||||||
|
shoulda (3.5.0)
|
||||||
|
shoulda-context (~> 1.0, >= 1.0.1)
|
||||||
|
shoulda-matchers (>= 1.4.1, < 3.0)
|
||||||
|
shoulda-context (1.2.1)
|
||||||
|
shoulda-matchers (2.8.0)
|
||||||
|
activesupport (>= 3.0.0)
|
||||||
|
simplecov (0.10.0)
|
||||||
|
docile (~> 1.1.0)
|
||||||
|
json (~> 1.8)
|
||||||
|
simplecov-html (~> 0.10.0)
|
||||||
|
simplecov-html (0.10.0)
|
||||||
|
thread_safe (0.3.5)
|
||||||
|
tzinfo (1.2.2)
|
||||||
|
thread_safe (~> 0.1)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
bundler (~> 1.0)
|
||||||
|
jeweler (~> 2.0.1)
|
||||||
|
rdoc (~> 3.12)
|
||||||
|
shoulda
|
||||||
|
simplecov
|
|
@ -0,0 +1,2 @@
|
||||||
|
module ReverseProxy
|
||||||
|
end
|
|
@ -0,0 +1,143 @@
|
||||||
|
require 'rack'
|
||||||
|
require 'rack-proxy'
|
||||||
|
|
||||||
|
module ReverseProxy
|
||||||
|
class Client
|
||||||
|
@@callback_methods = [
|
||||||
|
:on_response,
|
||||||
|
:on_set_cookies,
|
||||||
|
:on_success,
|
||||||
|
:on_redirect,
|
||||||
|
:on_missing,
|
||||||
|
:on_error,
|
||||||
|
:on_complete
|
||||||
|
]
|
||||||
|
|
||||||
|
# Define callback setters
|
||||||
|
@@callback_methods.each do |method|
|
||||||
|
define_method(method) do |&block|
|
||||||
|
self.callbacks[method] = block
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :url, :callbacks
|
||||||
|
|
||||||
|
def initialize(url)
|
||||||
|
self.url = url
|
||||||
|
self.callbacks = {}
|
||||||
|
|
||||||
|
# Initialize default callbacks with empty Proc
|
||||||
|
@@callback_methods.each do |method|
|
||||||
|
self.callbacks[method] = Proc.new {}
|
||||||
|
end
|
||||||
|
|
||||||
|
yield(self) if block_given?
|
||||||
|
end
|
||||||
|
|
||||||
|
def request(env, options = {}, &block)
|
||||||
|
options.reverse_merge!(
|
||||||
|
headers: {},
|
||||||
|
path: nil,
|
||||||
|
username: nil,
|
||||||
|
password: nil
|
||||||
|
)
|
||||||
|
|
||||||
|
source_request = Rack::Request.new(env)
|
||||||
|
|
||||||
|
# We can pass in a custom path
|
||||||
|
uri = URI.parse("#{url}#{options[:path] || env['ORIGINAL_FULLPATH']}")
|
||||||
|
|
||||||
|
# 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).merge(options[:headers])
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# Hold the response here
|
||||||
|
target_response = nil
|
||||||
|
|
||||||
|
# Don't encode response/support compression which was
|
||||||
|
# causing content length not match the actual content
|
||||||
|
# length of the response which ended up causing issues
|
||||||
|
# within Varnish (503)
|
||||||
|
target_request['Accept-Encoding'] = nil
|
||||||
|
|
||||||
|
# Make the request
|
||||||
|
Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == "https")) do |http|
|
||||||
|
target_response = http.request(target_request)
|
||||||
|
end
|
||||||
|
|
||||||
|
status_code = target_response.code.to_i
|
||||||
|
payload = [status_code, target_response]
|
||||||
|
|
||||||
|
callbacks[:on_response].call(payload)
|
||||||
|
|
||||||
|
if set_cookie_headers = target_response.to_hash['set-cookie']
|
||||||
|
set_cookies_hash = {}
|
||||||
|
|
||||||
|
set_cookie_headers.each do |set_cookie_header|
|
||||||
|
set_cookie_hash = CookieJar::CookieValidation.parse_set_cookie(set_cookie_header)
|
||||||
|
set_cookie_hash[:value] = CGI.unescape(set_cookie_hash[:value])
|
||||||
|
|
||||||
|
name = set_cookie_hash.delete(:name)
|
||||||
|
|
||||||
|
set_cookies_hash[name] = set_cookie_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
callbacks[:on_set_cookies].call(payload | [set_cookies_hash])
|
||||||
|
end
|
||||||
|
|
||||||
|
case status_code
|
||||||
|
when 200..299
|
||||||
|
callbacks[:on_success].call(payload)
|
||||||
|
when 300..399
|
||||||
|
if redirect_url = target_response['Location']
|
||||||
|
callbacks[:on_redirect].call(payload | [redirect_url])
|
||||||
|
end
|
||||||
|
when 400..499
|
||||||
|
callbacks[:on_missing].call(payload)
|
||||||
|
when 500..599
|
||||||
|
callbacks[:on_error].call(payload)
|
||||||
|
end
|
||||||
|
|
||||||
|
callbacks[:on_complete].call(payload)
|
||||||
|
|
||||||
|
payload
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
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(Rack::Utils::HeaderHash.new) do |hash, k_v|
|
||||||
|
k, v = k_v
|
||||||
|
hash[k] = v
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
headers
|
||||||
|
end
|
||||||
|
|
||||||
|
def reconstruct_header_name(name)
|
||||||
|
name.sub(/^HTTP_/, "").gsub("_", "-")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,60 @@
|
||||||
|
module ReverseProxy
|
||||||
|
module Controller
|
||||||
|
def reverse_proxy(proxy_url, options = {})
|
||||||
|
proxy_uri = Addressable::URI.parse(proxy_url)
|
||||||
|
|
||||||
|
client = ReverseProxy::Client.new(proxy_url) do |config|
|
||||||
|
config.on_response do |code, response|
|
||||||
|
blacklist = [
|
||||||
|
'Connection', # Always close connection
|
||||||
|
'Transfer-Encoding', # Let Rails calculate this
|
||||||
|
'Content-Length' # Let Rails calculate this
|
||||||
|
]
|
||||||
|
|
||||||
|
response.each_capitalized do |key, value|
|
||||||
|
next if blacklist.include?(key)
|
||||||
|
|
||||||
|
headers[key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
config.on_set_cookies do |code, response, set_cookies|
|
||||||
|
set_cookies.each do |key, attributes|
|
||||||
|
cookies[key] = attributes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
config.on_redirect do |code, response, redirect_url|
|
||||||
|
request_uri = Addressable::URI.parse(request.url)
|
||||||
|
redirect_uri = Addressable::URI.parse(redirect_url)
|
||||||
|
|
||||||
|
# Make redirect uri absolute if it's relative by
|
||||||
|
# joining it with the request url
|
||||||
|
redirect_uri = request_uri.join(redirect_url) if redirect_uri.host.nil?
|
||||||
|
|
||||||
|
unless redirect_uri.port.nil?
|
||||||
|
# Make sure it's consistent with our request port
|
||||||
|
redirect_uri.port = request.port if redirect_uri.port == proxy_uri.port
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to redirect_uri.to_s, status: code and return
|
||||||
|
end
|
||||||
|
|
||||||
|
config.on_complete do |code, response|
|
||||||
|
content_type = response['Content-Type']
|
||||||
|
body = response.body.to_s
|
||||||
|
|
||||||
|
if content_type and content_type.match /image/
|
||||||
|
send_data body, content_type: content_type, disposition: "inline", status: code
|
||||||
|
else
|
||||||
|
render text: body, content_type: content_type, status: code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
yield(config) if block_given?
|
||||||
|
end
|
||||||
|
|
||||||
|
client.request(env, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue