rack-reverse-proxy-ty 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +56 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/lib/rack/reverse_proxy.rb +176 -0
- data/rack-reverse-proxy-ty.gemspec +42 -0
- data/spec/rack/reverse_proxy_spec.rb +231 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +13 -0
- metadata +141 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 998bc49106c54f43f5981eb85a8a97c955359195
|
4
|
+
data.tar.gz: c0a1b3267a875a0b67c0039d9f7b2ef8c5871b2a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ab9c0de17f186ef32789c0e4805ec736820983e5304ded15be994587441d48b7902a1bf22312a7a90f671366e5409fb941773af013cbabdd14559bf597e372d3
|
7
|
+
data.tar.gz: c72582ff51ab8f18c20ce090bef674e943b06d2fef487e7c1ec0a755423eaf72fdbd2f59595ebae34f4eab42e796092c2e5432457c728abe53c426e568463313
|
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jon Swope
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
= A Reverse Proxy for Rack
|
2
|
+
|
3
|
+
This is a simple reverse proxy for Rack that pretty heavily rips off Rack Forwarder. It is not meant for production systems (although it may work), as the webserver fronting your app is generally much better at this sort of thing.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
The gem is available on gemcutter. Assuming you have a recent version of Rubygems you should just be able to install it via:
|
7
|
+
gem install rack-reverse-proxy
|
8
|
+
|
9
|
+
For your Gemfile use:
|
10
|
+
gem "rack-reverse-proxy", :require => "rack/reverse_proxy"
|
11
|
+
|
12
|
+
== Usage
|
13
|
+
Matchers can be a regex or a string. If a regex is used, you can use the subcaptures in your forwarding url by denoting them with a $.
|
14
|
+
|
15
|
+
Right now if more than one matcher matches any given route, it throws an exception for an ambiguous match. This will probably change later. If no match is found, the call is forwarded to your application.
|
16
|
+
|
17
|
+
Below is an example for configuring the middleware:
|
18
|
+
|
19
|
+
require 'rack/reverse_proxy'
|
20
|
+
|
21
|
+
use Rack::ReverseProxy do
|
22
|
+
# Set :preserve_host to true globally (default is true already)
|
23
|
+
reverse_proxy_options :preserve_host => true
|
24
|
+
|
25
|
+
# Forward the path /test* to http://example.com/test*
|
26
|
+
reverse_proxy '/test', 'http://example.com/'
|
27
|
+
|
28
|
+
# Forward the path /foo/* to http://example.com/bar/*
|
29
|
+
reverse_proxy /^\/foo(\/.*)$/, 'http://example.com/bar$1', :username => 'name', :password => 'basic_auth_secret'
|
30
|
+
end
|
31
|
+
|
32
|
+
app = proc do |env|
|
33
|
+
[ 200, {'Content-Type' => 'text/plain'}, "b" ]
|
34
|
+
end
|
35
|
+
run app
|
36
|
+
|
37
|
+
reverse_proxy_options sets global options for all reverse proxies. Available options are:
|
38
|
+
* :preserve_host Set to false to omit Host headers
|
39
|
+
* :username username for basic auth
|
40
|
+
* :password password for basic auth
|
41
|
+
* :matching is a global only option, if set to :first the first matched url will be requested (no ambigous error). Default: :all.
|
42
|
+
* :timeout seconds to timout the requests
|
43
|
+
|
44
|
+
== Note on Patches/Pull Requests
|
45
|
+
|
46
|
+
* Fork the project.
|
47
|
+
* Make your feature addition or bug fix.
|
48
|
+
* Add tests for it. This is important so I don't break it in a
|
49
|
+
future version unintentionally.
|
50
|
+
* Commit, do not mess with rakefile, version, or history.
|
51
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
52
|
+
* Send me a pull request. Bonus points for topic branches.
|
53
|
+
|
54
|
+
== Copyright
|
55
|
+
|
56
|
+
Copyright (c) 2010 Jon Swope. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
7
|
+
spec.libs << 'lib' << 'spec'
|
8
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
9
|
+
end
|
10
|
+
|
11
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
12
|
+
spec.libs << 'lib' << 'spec'
|
13
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
14
|
+
spec.rcov = true
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => :spec
|
18
|
+
|
19
|
+
require 'rake/rdoctask'
|
20
|
+
Rake::RDocTask.new do |rdoc|
|
21
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
22
|
+
|
23
|
+
rdoc.rdoc_dir = 'rdoc'
|
24
|
+
rdoc.title = "rack-reverse-proxy #{version}"
|
25
|
+
rdoc.rdoc_files.include('README*')
|
26
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
27
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.4.4
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class ReverseProxy
|
6
|
+
def initialize(app = nil, &b)
|
7
|
+
@app = app || lambda {|env| [404, [], []] }
|
8
|
+
@matchers = []
|
9
|
+
@global_options = {:preserve_host => true, :x_forwarded_host => true, :matching => :all, :verify_ssl => true}
|
10
|
+
instance_eval &b if block_given?
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
rackreq = Rack::Request.new(env)
|
15
|
+
matcher = get_matcher rackreq.fullpath
|
16
|
+
return @app.call(env) if matcher.nil?
|
17
|
+
|
18
|
+
uri = matcher.get_uri(rackreq.fullpath,env)
|
19
|
+
all_opts = @global_options.dup.merge(matcher.options)
|
20
|
+
headers = Rack::Utils::HeaderHash.new
|
21
|
+
env.each { |key, value|
|
22
|
+
if key =~ /HTTP_(.*)/
|
23
|
+
headers[$1] = value
|
24
|
+
end
|
25
|
+
}
|
26
|
+
headers['HOST'] = uri.host if all_opts[:preserve_host]
|
27
|
+
headers['X-Forwarded-Host'] = rackreq.host if all_opts[:x_forwarded_host]
|
28
|
+
|
29
|
+
session = Net::HTTP.new(uri.host, uri.port)
|
30
|
+
session.read_timeout=all_opts[:timeout] if all_opts[:timeout]
|
31
|
+
|
32
|
+
session.use_ssl = (uri.scheme == 'https')
|
33
|
+
if uri.scheme == 'https' && all_opts[:verify_ssl]
|
34
|
+
session.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
35
|
+
else
|
36
|
+
# DO NOT DO THIS IN PRODUCTION !!!
|
37
|
+
session.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
38
|
+
end
|
39
|
+
session.start { |http|
|
40
|
+
m = rackreq.request_method
|
41
|
+
case m
|
42
|
+
when "GET", "HEAD", "DELETE", "OPTIONS", "TRACE"
|
43
|
+
req = Net::HTTP.const_get(m.capitalize).new(uri.request_uri, headers)
|
44
|
+
req.basic_auth all_opts[:username], all_opts[:password] if all_opts[:username] and all_opts[:password]
|
45
|
+
when "PUT", "POST"
|
46
|
+
req = Net::HTTP.const_get(m.capitalize).new(uri.request_uri, headers)
|
47
|
+
req.basic_auth all_opts[:username], all_opts[:password] if all_opts[:username] and all_opts[:password]
|
48
|
+
|
49
|
+
if rackreq.body.respond_to?(:read) && rackreq.body.respond_to?(:rewind)
|
50
|
+
body = rackreq.body.read
|
51
|
+
req.content_length = body.size
|
52
|
+
rackreq.body.rewind
|
53
|
+
else
|
54
|
+
req.content_length = rackreq.body.size
|
55
|
+
end
|
56
|
+
|
57
|
+
req.content_type = rackreq.content_type unless rackreq.content_type.nil?
|
58
|
+
req.body_stream = rackreq.body
|
59
|
+
else
|
60
|
+
raise "method not supported: #{m}"
|
61
|
+
end
|
62
|
+
|
63
|
+
body = ''
|
64
|
+
res = http.request(req) do |res|
|
65
|
+
res.read_body do |segment|
|
66
|
+
body << segment
|
67
|
+
# ensure content length header is correct
|
68
|
+
res.content_length = body.bytesize
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
[res.code, create_response_headers(res), [body]]
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def get_matcher path
|
79
|
+
matches = @matchers.select do |matcher|
|
80
|
+
matcher.match?(path)
|
81
|
+
end
|
82
|
+
|
83
|
+
if matches.length < 1
|
84
|
+
nil
|
85
|
+
elsif matches.length > 1 && @global_options[:matching] != :first
|
86
|
+
raise AmbiguousProxyMatch.new(path, matches)
|
87
|
+
else
|
88
|
+
matches.first
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_response_headers http_response
|
93
|
+
response_headers = Rack::Utils::HeaderHash.new(http_response.to_hash)
|
94
|
+
# handled by Rack
|
95
|
+
response_headers.delete('status')
|
96
|
+
# TODO: figure out how to handle chunked responses
|
97
|
+
response_headers.delete('transfer-encoding')
|
98
|
+
# TODO: Verify Content Length, and required Rack headers
|
99
|
+
response_headers
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def reverse_proxy_options(options)
|
104
|
+
@global_options=options
|
105
|
+
end
|
106
|
+
|
107
|
+
def reverse_proxy matcher, url, opts={}
|
108
|
+
raise GenericProxyURI.new(url) if matcher.is_a?(String) && url.is_a?(String) && URI(url).class == URI::Generic
|
109
|
+
@matchers << ReverseProxyMatcher.new(matcher,url,opts)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class GenericProxyURI < Exception
|
114
|
+
attr_reader :url
|
115
|
+
|
116
|
+
def intialize(url)
|
117
|
+
@url = url
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_s
|
121
|
+
%Q(Your URL "#{@url}" is too generic. Did you mean "http://#{@url}"?)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class AmbiguousProxyMatch < Exception
|
126
|
+
attr_reader :path, :matches
|
127
|
+
def initialize(path, matches)
|
128
|
+
@path = path
|
129
|
+
@matches = matches
|
130
|
+
end
|
131
|
+
|
132
|
+
def to_s
|
133
|
+
%Q(Path "#{path}" matched multiple endpoints: #{formatted_matches})
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def formatted_matches
|
139
|
+
matches.map {|matcher| matcher.to_s}.join(', ')
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class ReverseProxyMatcher
|
144
|
+
def initialize(matching,url,options)
|
145
|
+
@matching=matching
|
146
|
+
@url=url
|
147
|
+
@options=options
|
148
|
+
@matching_regexp= matching.kind_of?(Regexp) ? matching : /^#{matching.to_s}/
|
149
|
+
end
|
150
|
+
|
151
|
+
attr_reader :matching,:matching_regexp,:url,:options
|
152
|
+
|
153
|
+
def match?(path)
|
154
|
+
match_path(path) ? true : false
|
155
|
+
end
|
156
|
+
|
157
|
+
def get_uri(path,env)
|
158
|
+
_url=(url.respond_to?(:call) ? url.call(env) : url.clone)
|
159
|
+
if _url =~/\$\d/
|
160
|
+
match_path(path).to_a.each_with_index { |m, i| _url.gsub!("$#{i.to_s}", m) }
|
161
|
+
URI(_url)
|
162
|
+
else
|
163
|
+
URI.join(_url, path)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
def to_s
|
167
|
+
%Q("#{matching.to_s}" => "#{url}")
|
168
|
+
end
|
169
|
+
private
|
170
|
+
def match_path(path)
|
171
|
+
path.match(matching_regexp)
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{rack-reverse-proxy-ty}
|
3
|
+
s.version = "0.4.4"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["TY"]
|
7
|
+
s.date = %q{2012-01-26}
|
8
|
+
s.description = %q{A Rack based reverse proxy for basic needs. Useful for testing or in cases where webserver configuration is unavailable.}
|
9
|
+
s.email = %q{ty@gmail.com}
|
10
|
+
s.extra_rdoc_files = [
|
11
|
+
"LICENSE",
|
12
|
+
"README.rdoc"
|
13
|
+
]
|
14
|
+
s.files = [
|
15
|
+
".document",
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc",
|
18
|
+
"Rakefile",
|
19
|
+
"VERSION",
|
20
|
+
"lib/rack/reverse_proxy.rb",
|
21
|
+
"rack-reverse-proxy-ty.gemspec",
|
22
|
+
"spec/rack/reverse_proxy_spec.rb",
|
23
|
+
"spec/spec.opts",
|
24
|
+
"spec/spec_helper.rb"
|
25
|
+
]
|
26
|
+
s.homepage = %q{http://github.com/prismaticence/rack-reverse-proxy-ty}
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
s.rubygems_version = %q{1.3.7}
|
29
|
+
s.summary = %q{A Simple Reverse Proxy for Rack}
|
30
|
+
s.test_files = [
|
31
|
+
"spec/rack/reverse_proxy_spec.rb",
|
32
|
+
"spec/spec_helper.rb"
|
33
|
+
]
|
34
|
+
|
35
|
+
s.add_development_dependency "rspec", "~> 1.3.2"
|
36
|
+
s.add_development_dependency "bundler", "~> 1.0.15"
|
37
|
+
s.add_development_dependency "rake", "~> 0.8.7"
|
38
|
+
s.add_development_dependency "rack-test", "~> 0.5.7"
|
39
|
+
s.add_development_dependency "webmock", "~> 1.5.0"
|
40
|
+
s.add_dependency "rack", ">= 1.0.0"
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Rack::ReverseProxy do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
include WebMock::API
|
6
|
+
|
7
|
+
def app
|
8
|
+
Rack::ReverseProxy.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def dummy_app
|
12
|
+
lambda { |env| [200, {}, ['Dummy App']] }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "as middleware" do
|
16
|
+
def app
|
17
|
+
Rack::ReverseProxy.new(dummy_app) do
|
18
|
+
reverse_proxy '/test', 'http://example.com/', {:preserve_host => true}
|
19
|
+
reverse_proxy '/2test', lambda{ |env| 'http://example.com/'}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should forward requests to the calling app when the path is not matched" do
|
24
|
+
get '/'
|
25
|
+
last_response.body.should == "Dummy App"
|
26
|
+
last_response.should be_ok
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should proxy requests when a pattern is matched" do
|
30
|
+
stub_request(:get, 'http://example.com/test').to_return({:body => "Proxied App"})
|
31
|
+
get '/test'
|
32
|
+
last_response.body.should == "Proxied App"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should proxy requests to a lambda url when a pattern is matched" do
|
36
|
+
stub_request(:get, 'http://example.com/2test').to_return({:body => "Proxied App2"})
|
37
|
+
get '/2test'
|
38
|
+
last_response.body.should == "Proxied App2"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "the response header should never contain Status" do
|
42
|
+
stub_request(:any, 'example.com/test/stuff').to_return(:headers => {'Status' => '200 OK'})
|
43
|
+
get '/test/stuff'
|
44
|
+
last_response.headers['Status'].should == nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "the response header should never transfer-encoding" do
|
48
|
+
stub_request(:any, 'example.com/test/stuff').to_return(:headers => {'transfer-encoding' => 'Chunked'})
|
49
|
+
get '/test/stuff'
|
50
|
+
last_response.headers['transfer-encoding'].should == nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should set the Host header" do
|
54
|
+
stub_request(:any, 'example.com/test/stuff')
|
55
|
+
get '/test/stuff'
|
56
|
+
a_request(:get, 'http://example.com/test/stuff').with(:headers => {"Host" => "example.com"}).should have_been_made
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should set the X-Forwarded-Host header to the proxying host by default" do
|
60
|
+
stub_request(:any, 'example.com/test/stuff')
|
61
|
+
get '/test/stuff'
|
62
|
+
a_request(:get, 'http://example.com/test/stuff').with(:headers => {'X-Forwarded-Host' => 'example.org'}).should have_been_made
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "with preserve host turned off" do
|
66
|
+
def app
|
67
|
+
Rack::ReverseProxy.new(dummy_app) do
|
68
|
+
reverse_proxy '/test', 'http://example.com/', {:preserve_host => false}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not set the Host header" do
|
73
|
+
stub_request(:any, 'example.com/test/stuff')
|
74
|
+
get '/test/stuff'
|
75
|
+
a_request(:get, 'http://example.com/test/stuff').with(:headers => {"Host" => "example.com"}).should_not have_been_made
|
76
|
+
a_request(:get, 'http://example.com/test/stuff').should have_been_made
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "with x_forwarded_host turned off" do
|
81
|
+
def app
|
82
|
+
Rack::ReverseProxy.new(dummy_app) do
|
83
|
+
reverse_proxy_options :x_forwarded_host => false
|
84
|
+
reverse_proxy '/test', 'http://example.com/'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should not set the X-Forwarded-Host header to the proxying host" do
|
89
|
+
stub_request(:any, 'example.com/test/stuff')
|
90
|
+
get '/test/stuff'
|
91
|
+
a_request(:get, 'http://example.com/test/stuff').with(:headers => {'X-Forwarded-Host' => 'example.org'}).should_not have_been_made
|
92
|
+
a_request(:get, 'http://example.com/test/stuff').should have_been_made
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "with basic auth turned on" do
|
97
|
+
def app
|
98
|
+
Rack::ReverseProxy.new(dummy_app) do
|
99
|
+
reverse_proxy '/test', 'http://example.com/', {:username => "joe", :password => "shmoe"}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should make request with basic auth" do
|
104
|
+
stub_request(:get, "http://joe:shmoe@example.com/test/stuff").to_return(:body => "secured content")
|
105
|
+
get '/test/stuff'
|
106
|
+
last_response.body.should == "secured content"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "with ambiguous routes and all matching" do
|
111
|
+
def app
|
112
|
+
Rack::ReverseProxy.new(dummy_app) do
|
113
|
+
reverse_proxy_options :matching => :all
|
114
|
+
reverse_proxy '/test', 'http://example.com/'
|
115
|
+
reverse_proxy /^\/test/, 'http://example.com/'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should throw an exception" do
|
120
|
+
lambda { get '/test' }.should raise_error(Rack::AmbiguousProxyMatch)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "with ambiguous routes and first matching" do
|
125
|
+
def app
|
126
|
+
Rack::ReverseProxy.new(dummy_app) do
|
127
|
+
reverse_proxy_options :matching => :first
|
128
|
+
reverse_proxy '/test', 'http://example1.com/'
|
129
|
+
reverse_proxy /^\/test/, 'http://example2.com/'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should throw an exception" do
|
134
|
+
stub_request(:get, 'http://example1.com/test').to_return({:body => "Proxied App"})
|
135
|
+
get '/test'
|
136
|
+
last_response.body.should == "Proxied App"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "with a route as a regular expression" do
|
141
|
+
def app
|
142
|
+
Rack::ReverseProxy.new(dummy_app) do
|
143
|
+
reverse_proxy %r|^/test(/.*)$|, 'http://example.com$1'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should support subcaptures" do
|
148
|
+
stub_request(:get, 'http://example.com/path').to_return({:body => "Proxied App"})
|
149
|
+
get '/test/path'
|
150
|
+
last_response.body.should == "Proxied App"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "with a https route" do
|
155
|
+
def app
|
156
|
+
Rack::ReverseProxy.new(dummy_app) do
|
157
|
+
reverse_proxy '/test', 'https://example.com'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should make a secure request" do
|
162
|
+
stub_request(:get, 'https://example.com/test/stuff').to_return({:body => "Proxied Secure App"})
|
163
|
+
get '/test/stuff'
|
164
|
+
last_response.body.should == "Proxied Secure App"
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "with a route as a string" do
|
170
|
+
def app
|
171
|
+
Rack::ReverseProxy.new(dummy_app) do
|
172
|
+
reverse_proxy '/test', 'http://example.com'
|
173
|
+
reverse_proxy '/path', 'http://example.com/foo$0'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should append the full path to the uri" do
|
178
|
+
stub_request(:get, 'http://example.com/test/stuff').to_return({:body => "Proxied App"})
|
179
|
+
get '/test/stuff'
|
180
|
+
last_response.body.should == "Proxied App"
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "with a generic url" do
|
186
|
+
def app
|
187
|
+
Rack::ReverseProxy.new(dummy_app) do
|
188
|
+
reverse_proxy '/test', 'example.com'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should throw an exception" do
|
193
|
+
lambda{ app }.should raise_error(Rack::GenericProxyURI)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "with a matching route" do
|
198
|
+
def app
|
199
|
+
Rack::ReverseProxy.new(dummy_app) do
|
200
|
+
reverse_proxy '/test', 'http://example.com/'
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
%w|get head delete put post|.each do |method|
|
205
|
+
describe "and using method #{method}" do
|
206
|
+
it "should forward the correct request" do
|
207
|
+
stub_request(method.to_sym, 'http://example.com/test').to_return({:body => "Proxied App for #{method}"})
|
208
|
+
eval "#{method} '/test'"
|
209
|
+
last_response.body.should == "Proxied App for #{method}"
|
210
|
+
end
|
211
|
+
|
212
|
+
if %w|put post|.include?(method)
|
213
|
+
it "should forward the request payload" do
|
214
|
+
stub_request(method.to_sym, 'http://example.com/test').to_return { |req| {:body => req.body} }
|
215
|
+
eval "#{method} '/test', {:test => 'test'}"
|
216
|
+
last_response.body.should == "test=test"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe "as a rack app" do
|
225
|
+
it "should respond with 404 when the path is not matched" do
|
226
|
+
get '/'
|
227
|
+
last_response.should be_not_found
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'rack/reverse_proxy'
|
4
|
+
require 'spec'
|
5
|
+
require 'spec/autorun'
|
6
|
+
require 'rubygems'
|
7
|
+
require 'rack/test'
|
8
|
+
require 'webmock'
|
9
|
+
require 'webmock/rspec'
|
10
|
+
|
11
|
+
Spec::Runner.configure do |config|
|
12
|
+
WebMock.disable_net_connect!
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack-reverse-proxy-ty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TY
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2012-01-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.3.2
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.3.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.15
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.15
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.7
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.7
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack-test
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.5.7
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.5.7
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.5.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.5.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rack
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.0.0
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.0.0
|
97
|
+
description: A Rack based reverse proxy for basic needs. Useful for testing or in
|
98
|
+
cases where webserver configuration is unavailable.
|
99
|
+
email: ty@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files:
|
103
|
+
- LICENSE
|
104
|
+
- README.rdoc
|
105
|
+
files:
|
106
|
+
- ".document"
|
107
|
+
- LICENSE
|
108
|
+
- README.rdoc
|
109
|
+
- Rakefile
|
110
|
+
- VERSION
|
111
|
+
- lib/rack/reverse_proxy.rb
|
112
|
+
- rack-reverse-proxy-ty.gemspec
|
113
|
+
- spec/rack/reverse_proxy_spec.rb
|
114
|
+
- spec/spec.opts
|
115
|
+
- spec/spec_helper.rb
|
116
|
+
homepage: http://github.com/prismaticence/rack-reverse-proxy-ty
|
117
|
+
licenses: []
|
118
|
+
metadata: {}
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
requirements: []
|
134
|
+
rubyforge_project:
|
135
|
+
rubygems_version: 2.2.2
|
136
|
+
signing_key:
|
137
|
+
specification_version: 4
|
138
|
+
summary: A Simple Reverse Proxy for Rack
|
139
|
+
test_files:
|
140
|
+
- spec/rack/reverse_proxy_spec.rb
|
141
|
+
- spec/spec_helper.rb
|