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