-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit bcafe86
Showing
7 changed files
with
237 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
*.gem | ||
.bundle | ||
Gemfile.lock | ||
pkg/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
source "http://rubygems.org" | ||
|
||
# Specify your gem's dependencies in middleman-proxy.gemspec | ||
gemspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
require 'bundler' | ||
Bundler::GemHelper.install_tasks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
# =========================================================================== | ||
# Original Project: Abbot - SproutCore Build Tools | ||
# Copyright: ©2009 Apple Inc. | ||
# portions copyright @2006-2011 Strobe Inc. | ||
# and contributors | ||
# =========================================================================== | ||
|
||
begin | ||
require 'net/https' | ||
Middleman::HTTPS_ENABLED = true | ||
rescue LoadError => e | ||
require 'net/http' | ||
Middleman::HTTPS_ENABLED = false | ||
end | ||
|
||
module Middleman | ||
module Features | ||
module Proxy | ||
|
||
class << self | ||
def registered(app) | ||
app.extend ClassMethods | ||
app.use Middleman::Features::Proxy::Rack | ||
end | ||
alias :included :registered | ||
end | ||
|
||
class Collection | ||
def initialize(app) | ||
@app = app | ||
end | ||
|
||
def self.proxies | ||
@@proxies ||= {} | ||
end | ||
|
||
def self.add(path, options={}) | ||
@@proxies ||= {} | ||
@@proxies[path] = options[:to] | ||
end | ||
end | ||
|
||
module ClassMethods | ||
# Proxies requests to the path | ||
# | ||
# proxy '/twitter', "http://twitter/web/service" | ||
def proxy(path, options={}) | ||
Middleman::Features::Proxy::Collection.add(path, options) | ||
end | ||
end | ||
|
||
# Rack application proxies requests as needed for the given project. | ||
module Rack | ||
|
||
def initialize(app) | ||
@app = app | ||
end | ||
|
||
def call(env) | ||
url = env['PATH_INFO'] | ||
|
||
@proxies = Middleman::Features::Proxy::Collection.proxies | ||
@proxies.each do |proxy, value| | ||
if url.match(/^#{Regexp.escape(proxy.to_s)}/) | ||
return handle_proxy(value, proxy.to_s, env) | ||
end | ||
end | ||
|
||
return [404, {}, "not found"] | ||
end | ||
|
||
def handle_proxy(proxy, proxy_url, env) | ||
if proxy[:secure] && !Middleman::HTTPS_ENABLED | ||
$stderr.puts "~ WARNING: HTTPS is not supported on your system, using HTTP instead.\n" | ||
$stderr.puts" If you are using Ubuntu, you can run `apt-get install libopenssl-ruby`\n" | ||
proxy[:secure] = false | ||
end | ||
|
||
origin_host = env['SERVER_NAME'] # capture the origin host for cookies | ||
http_method = env['REQUEST_METHOD'].to_s.downcase | ||
url = env['PATH_INFO'] | ||
params = env['QUERY_STRING'] | ||
|
||
# collect headers... | ||
headers = {} | ||
env.each do |key, value| | ||
next unless key =~ /^HTTP_/ | ||
key = key.gsub(/^HTTP_/,'').downcase.sub(/^\w/){|l| l.upcase}.gsub(/_(\w)/){|l| "-#{$1.upcase}"} # remove HTTP_, dasherize and titleize | ||
if !key.eql? "Version" | ||
headers[key] = value | ||
end | ||
end | ||
|
||
# Rack documentation says CONTENT_TYPE and CONTENT_LENGTH aren't prefixed by HTTP_ | ||
headers['Content-Type'] = env['CONTENT_TYPE'] if env['CONTENT_TYPE'] | ||
|
||
length = env['CONTENT_LENGTH'] | ||
headers['Content-Length'] = length if length | ||
|
||
http_host, http_port = proxy[:to].split(':') | ||
http_port = proxy[:secure] ? '443' : '80' if http_port.nil? | ||
|
||
# added 4/23/09 per Charles Jolley, corrects problem | ||
# when making requests to virtual hosts | ||
headers['Host'] = "#{http_host}:#{http_port}" | ||
|
||
if proxy[:url] | ||
url = url.sub(/^#{Regexp.escape proxy_url}/, proxy[:url]) | ||
end | ||
|
||
http_path = [url] | ||
http_path << params if params && params.size>0 | ||
http_path = http_path.join('?') | ||
|
||
response = nil | ||
no_body_method = %w(get copy head move options trace) | ||
|
||
done = false | ||
tries = 0 | ||
until done | ||
http = ::Net::HTTP.new(http_host, http_port) | ||
|
||
if proxy[:secure] | ||
http.use_ssl = true | ||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE | ||
end | ||
|
||
http.start do |web| | ||
if no_body_method.include?(http_method) | ||
response = web.send(http_method, http_path, headers) | ||
else | ||
http_body = env['rack.input'] | ||
http_body.rewind # May not be necessary but can't hurt | ||
|
||
req = Net::HTTPGenericRequest.new(http_method.upcase, | ||
true, true, http_path, headers) | ||
req.body_stream = http_body if length.to_i > 0 | ||
response = web.request(req) | ||
end | ||
end | ||
|
||
status = response.code # http status code | ||
protocol = proxy[:secure] ? 'https' : 'http' | ||
|
||
$stderr.puts "~ PROXY: #{http_method.upcase} #{status} #{url} -> #{protocol}://#{http_host}:#{http_port}#{http_path}\n" | ||
|
||
# display and construct specific response headers | ||
response_headers = {} | ||
ignore_headers = ['transfer-encoding', 'keep-alive', 'connection'] | ||
response.each do |key, value| | ||
next if ignore_headers.include?(key.downcase) | ||
# If this is a cookie, strip out the domain. This technically may | ||
# break certain scenarios where services try to set cross-domain | ||
# cookies, but those services should not be doing that anyway... | ||
value.gsub!(/domain=[^\;]+\;? ?/,'') if key.downcase == 'set-cookie' | ||
# Location headers should rewrite the hostname if it is included. | ||
value.gsub!(/^http:\/\/#{http_host}(:[0-9]+)?\//, "http://#{http_host}/") if key.downcase == 'location' | ||
# content-length is returning char count not bytesize | ||
if key.downcase == 'content-length' | ||
if response.body.respond_to?(:bytesize) | ||
value = response.body.bytesize.to_s | ||
elsif response.body.respond_to?(:size) | ||
value = response.body.size.to_s | ||
else | ||
value = '0' | ||
end | ||
end | ||
|
||
$stderr.puts << " #{key}: #{value}\n" | ||
response_headers[key] = value | ||
end | ||
|
||
if [301, 302, 303, 307].include?(status.to_i) && proxy[:redirect] != false | ||
$stderr.puts '~ REDIRECTING: '+response_headers['location']+"\n" | ||
|
||
uri = URI.parse(response_headers['location']); | ||
http_host = uri.host | ||
http_port = uri.port | ||
http_path = uri.path | ||
http_path += '?'+uri.query if uri.query | ||
|
||
tries += 1 | ||
if tries > 10 | ||
raise "Too many redirects!" | ||
end | ||
else | ||
done = true | ||
end | ||
end | ||
|
||
# Thin doesn't like null bodies | ||
response_body = response.body || '' | ||
|
||
return [status, ::Rack::Utils::HeaderHash.new(response_headers), [response_body]] | ||
end | ||
end | ||
|
||
end | ||
end | ||
end |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module Middleman | ||
module Proxy | ||
VERSION = "0.0.1" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# -*- encoding: utf-8 -*- | ||
$:.push File.expand_path("../lib", __FILE__) | ||
require "middleman-proxy/version" | ||
|
||
Gem::Specification.new do |s| | ||
s.name = "middleman-proxy" | ||
s.version = Middleman::Proxy::VERSION | ||
s.platform = Gem::Platform::RUBY | ||
s.authors = ["Thomas Reynolds"] | ||
s.email = ["[email protected]"] | ||
s.homepage = "https://github.com/tdreyno/middleman-proxy" | ||
s.summary = %q{Remote Data for your Middleman Project} | ||
|
||
s.rubyforge_project = "middleman-proxy" | ||
|
||
s.files = `git ls-files`.split("\n") | ||
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") | ||
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } | ||
s.require_paths = ["lib"] | ||
|
||
s.add_runtime_dependency("middleman", ["~> 2.0.0"]) | ||
end |