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 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
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
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
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format specdoc
@@ -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