rack-reverse-proxy 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +6 -1
- data/Rakefile +13 -19
- data/VERSION +1 -1
- data/lib/rack/reverse_proxy.rb +69 -43
- data/rack-reverse-proxy.gemspec +17 -10
- data/spec/rack/reverse_proxy_spec.rb +125 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +12 -0
- metadata +55 -17
- data/test/helper.rb +0 -10
- data/test/test_rack-reverse-proxy.rb +0 -4
data/README.rdoc
CHANGED
@@ -2,13 +2,18 @@
|
|
2
2
|
|
3
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
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
|
+
== Usage
|
5
10
|
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 $.
|
6
11
|
|
7
12
|
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.
|
8
13
|
|
9
14
|
Below is an example for configuring the middleware:
|
10
15
|
|
11
|
-
require '
|
16
|
+
require 'rack/reverse_proxy'
|
12
17
|
|
13
18
|
use Rack::ReverseProxy do
|
14
19
|
# Forward the path /test* to http://example.com/test*
|
data/Rakefile
CHANGED
@@ -10,7 +10,9 @@ begin
|
|
10
10
|
gem.email = "jaswope@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/jaswope/rack-reverse-proxy"
|
12
12
|
gem.authors = ["Jon Swope"]
|
13
|
-
gem.add_development_dependency "
|
13
|
+
gem.add_development_dependency "rspec", ">= 0"
|
14
|
+
gem.add_development_dependency "rack-test", ">= 0"
|
15
|
+
gem.add_development_dependency "webmock", ">= 0"
|
14
16
|
gem.add_dependency "rack", ">= 1.0.0"
|
15
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
18
|
end
|
@@ -19,29 +21,21 @@ rescue LoadError
|
|
19
21
|
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
22
|
end
|
21
23
|
|
22
|
-
require 'rake/
|
23
|
-
Rake::
|
24
|
-
|
25
|
-
|
26
|
-
test.verbose = true
|
24
|
+
require 'spec/rake/spectask'
|
25
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
26
|
+
spec.libs << 'lib' << 'spec'
|
27
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
test.pattern = 'test/**/test_*.rb'
|
34
|
-
test.verbose = true
|
35
|
-
end
|
36
|
-
rescue LoadError
|
37
|
-
task :rcov do
|
38
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
-
end
|
30
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
31
|
+
spec.libs << 'lib' << 'spec'
|
32
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
33
|
+
spec.rcov = true
|
40
34
|
end
|
41
35
|
|
42
|
-
task :
|
36
|
+
task :spec => :check_dependencies
|
43
37
|
|
44
|
-
task :default => :
|
38
|
+
task :default => :spec
|
45
39
|
|
46
40
|
require 'rake/rdoctask'
|
47
41
|
Rake::RDocTask.new do |rdoc|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/rack/reverse_proxy.rb
CHANGED
@@ -13,73 +13,99 @@ module Rack
|
|
13
13
|
matcher, url = get_matcher_and_url rackreq.fullpath
|
14
14
|
return @app.call(env) if matcher.nil?
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
uri = case url
|
24
|
-
when /\$\d/
|
25
|
-
match.to_a.each_with_index { |m, i| url.gsub!("$#{i.to_s}", m) }
|
26
|
-
URI(url)
|
27
|
-
else
|
28
|
-
URI.join(url, path)
|
29
|
-
end
|
30
|
-
|
31
|
-
headers = Rack::Utils::HeaderHash.new
|
32
|
-
env.each { |key, value|
|
33
|
-
if key =~ /HTTP_(.*)/
|
34
|
-
headers[$1] = value
|
35
|
-
end
|
36
|
-
}
|
37
|
-
|
38
|
-
res = Net::HTTP.start(uri.host, uri.port) { |http|
|
39
|
-
m = rackreq.request_method
|
40
|
-
case m
|
41
|
-
when "GET", "HEAD", "DELETE", "OPTIONS", "TRACE"
|
42
|
-
req = Net::HTTP.const_get(m.capitalize).new(uri.path, headers)
|
43
|
-
when "PUT", "POST"
|
44
|
-
req = Net::HTTP.const_get(m.capitalize).new(uri.path, headers)
|
45
|
-
req.body_stream = rackreq.body
|
46
|
-
else
|
47
|
-
raise "method not supported: #{method}"
|
48
|
-
end
|
16
|
+
uri = get_uri(url, matcher, rackreq.fullpath)
|
17
|
+
headers = Rack::Utils::HeaderHash.new
|
18
|
+
env.each { |key, value|
|
19
|
+
if key =~ /HTTP_(.*)/
|
20
|
+
headers[$1] = value
|
21
|
+
end
|
22
|
+
}
|
49
23
|
|
50
|
-
|
51
|
-
|
24
|
+
res = Net::HTTP.start(uri.host, uri.port) { |http|
|
25
|
+
m = rackreq.request_method
|
26
|
+
case m
|
27
|
+
when "GET", "HEAD", "DELETE", "OPTIONS", "TRACE"
|
28
|
+
req = Net::HTTP.const_get(m.capitalize).new(uri.path, headers)
|
29
|
+
when "PUT", "POST"
|
30
|
+
req = Net::HTTP.const_get(m.capitalize).new(uri.path, headers)
|
31
|
+
req.body_stream = rackreq.body
|
32
|
+
else
|
33
|
+
raise "method not supported: #{method}"
|
34
|
+
end
|
35
|
+
|
36
|
+
http.request(req)
|
37
|
+
}
|
52
38
|
|
53
|
-
|
39
|
+
[res.code, Rack::Utils::HeaderHash.new(res.to_hash), [res.body]]
|
54
40
|
end
|
55
41
|
|
56
42
|
private
|
57
43
|
|
58
44
|
def get_matcher_and_url path
|
59
45
|
matches = @paths.select do |matcher, url|
|
60
|
-
|
61
|
-
when String
|
62
|
-
path =~ /^#{matcher}/
|
63
|
-
when Regexp
|
64
|
-
path =~ matcher
|
65
|
-
end
|
46
|
+
match_path(path, matcher)
|
66
47
|
end
|
67
48
|
|
68
49
|
if matches.length < 1
|
69
50
|
nil
|
70
51
|
elsif matches.length > 1
|
71
|
-
raise AmbiguousProxyMatch
|
52
|
+
raise AmbiguousProxyMatch.new(path, matches)
|
72
53
|
else
|
73
54
|
matches.first.map{|a| a.dup}
|
74
55
|
end
|
75
56
|
end
|
76
57
|
|
58
|
+
def match_path(path, matcher)
|
59
|
+
if matcher.is_a?(Regexp)
|
60
|
+
path.match(matcher)
|
61
|
+
else
|
62
|
+
path.match(/^#{matcher.to_s}/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_uri(url, matcher, path)
|
67
|
+
if url =~/\$\d/
|
68
|
+
match_path(path, matcher).to_a.each_with_index { |m, i| url.gsub!("$#{i.to_s}", m) }
|
69
|
+
URI(url)
|
70
|
+
else
|
71
|
+
URI.join(url, path)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
77
75
|
def reverse_proxy matcher, url
|
76
|
+
raise GenericProxyURI.new(url) if matcher.is_a?(String) && URI(url).class == URI::Generic
|
78
77
|
@paths.merge!(matcher => url)
|
79
78
|
end
|
80
79
|
end
|
81
80
|
|
81
|
+
class GenericProxyURI < Exception
|
82
|
+
attr_reader :url
|
83
|
+
|
84
|
+
def intialize(url)
|
85
|
+
@url = url
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
%Q(Your URL "#{@url}" is too generic. Did you mean "http://#{@url}"?)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
82
93
|
class AmbiguousProxyMatch < Exception
|
94
|
+
attr_reader :path, :matches
|
95
|
+
def initialize(path, matches)
|
96
|
+
@path = path
|
97
|
+
@matches = matches
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_s
|
101
|
+
%Q(Path "#{path}" matched multiple endpoints: #{formatted_matches})
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def formatted_matches
|
107
|
+
matches.map {|m| %Q("#{m[0].to_s}" => "#{m[1]}")}.join(', ')
|
108
|
+
end
|
83
109
|
end
|
84
110
|
|
85
111
|
end
|
data/rack-reverse-proxy.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rack-reverse-proxy}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jon Swope"]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-11}
|
13
13
|
s.description = %q{A Rack based reverse proxy for basic needs. Useful for testing or in cases where webserver configuration is unavailable.}
|
14
14
|
s.email = %q{jaswope@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,17 +26,18 @@ Gem::Specification.new do |s|
|
|
26
26
|
"VERSION",
|
27
27
|
"lib/rack/reverse_proxy.rb",
|
28
28
|
"rack-reverse-proxy.gemspec",
|
29
|
-
"
|
30
|
-
"
|
29
|
+
"spec/rack/reverse_proxy_spec.rb",
|
30
|
+
"spec/spec.opts",
|
31
|
+
"spec/spec_helper.rb"
|
31
32
|
]
|
32
33
|
s.homepage = %q{http://github.com/jaswope/rack-reverse-proxy}
|
33
34
|
s.rdoc_options = ["--charset=UTF-8"]
|
34
35
|
s.require_paths = ["lib"]
|
35
|
-
s.rubygems_version = %q{1.3.
|
36
|
+
s.rubygems_version = %q{1.3.6}
|
36
37
|
s.summary = %q{A Simple Reverse Proxy for Rack}
|
37
38
|
s.test_files = [
|
38
|
-
"
|
39
|
-
"
|
39
|
+
"spec/spec_helper.rb",
|
40
|
+
"spec/rack/reverse_proxy_spec.rb"
|
40
41
|
]
|
41
42
|
|
42
43
|
if s.respond_to? :specification_version then
|
@@ -44,14 +45,20 @@ Gem::Specification.new do |s|
|
|
44
45
|
s.specification_version = 3
|
45
46
|
|
46
47
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
47
|
-
s.add_development_dependency(%q<
|
48
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
49
|
+
s.add_development_dependency(%q<rack-test>, [">= 0"])
|
50
|
+
s.add_development_dependency(%q<webmock>, [">= 0"])
|
48
51
|
s.add_runtime_dependency(%q<rack>, [">= 1.0.0"])
|
49
52
|
else
|
50
|
-
s.add_dependency(%q<
|
53
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
54
|
+
s.add_dependency(%q<rack-test>, [">= 0"])
|
55
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
51
56
|
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
52
57
|
end
|
53
58
|
else
|
54
|
-
s.add_dependency(%q<
|
59
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
60
|
+
s.add_dependency(%q<rack-test>, [">= 0"])
|
61
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
55
62
|
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
56
63
|
end
|
57
64
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Rack::ReverseProxy do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
include WebMock
|
6
|
+
|
7
|
+
def app
|
8
|
+
Rack::ReverseProxy.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def dummy_app
|
12
|
+
lambda { [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/'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should forward requests to the calling app when the path is not matched" do
|
23
|
+
get '/'
|
24
|
+
last_response.body.should == "Dummy App"
|
25
|
+
last_response.should be_ok
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should proxy requests when a pattern is matched" do
|
29
|
+
stub_request(:get, 'http://example.com/test').to_return({:body => "Proxied App"})
|
30
|
+
get '/test'
|
31
|
+
last_response.body.should == "Proxied App"
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "with ambiguous routes" do
|
35
|
+
def app
|
36
|
+
Rack::ReverseProxy.new(dummy_app) do
|
37
|
+
reverse_proxy '/test', 'http://example.com/'
|
38
|
+
reverse_proxy /^\/test/, 'http://example.com/'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should throw an exception" do
|
43
|
+
lambda { get '/test' }.should raise_error(Rack::AmbiguousProxyMatch)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "with a route as a regular expression" do
|
48
|
+
def app
|
49
|
+
Rack::ReverseProxy.new(dummy_app) do
|
50
|
+
reverse_proxy %r|^/test(/.*)$|, 'http://example.com$1'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should support subcaptures" do
|
55
|
+
stub_request(:get, 'http://example.com/path').to_return({:body => "Proxied App"})
|
56
|
+
get '/test/path'
|
57
|
+
last_response.body.should == "Proxied App"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "with a route as a string" do
|
62
|
+
def app
|
63
|
+
Rack::ReverseProxy.new(dummy_app) do
|
64
|
+
reverse_proxy '/test', 'http://example.com'
|
65
|
+
reverse_proxy '/path', 'http://example.com/foo$0'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should append the full path to the uri" do
|
70
|
+
stub_request(:get, 'http://example.com/test/stuff').to_return({:body => "Proxied App"})
|
71
|
+
get '/test/stuff'
|
72
|
+
last_response.body.should == "Proxied App"
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "with a generic url" do
|
78
|
+
def app
|
79
|
+
Rack::ReverseProxy.new(dummy_app) do
|
80
|
+
reverse_proxy '/test', 'example.com'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should throw an exception" do
|
85
|
+
lambda{ app }.should raise_error(Rack::GenericProxyURI)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "with a matching route" do
|
90
|
+
def app
|
91
|
+
Rack::ReverseProxy.new(dummy_app) do
|
92
|
+
reverse_proxy '/test', 'http://example.com/'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
%w|get head delete put post|.each do |method|
|
97
|
+
describe "and using method #{method}" do
|
98
|
+
it "should forward the correct request" do
|
99
|
+
stub_request(method.to_sym, 'http://example.com/test').to_return({:body => "Proxied App for #{method}"})
|
100
|
+
eval "#{method} '/test'"
|
101
|
+
last_response.body.should == "Proxied App for #{method}"
|
102
|
+
end
|
103
|
+
|
104
|
+
if %w|put post|.include?(method)
|
105
|
+
it "should forward the request payload" do
|
106
|
+
pending "valid test with next release of WebMock" do
|
107
|
+
stub_request(method.to_sym, 'http://example.com/test').to_return { |req| {:body => req.body} }
|
108
|
+
eval "#{method} '/test', {:test => 'test'}"
|
109
|
+
last_response.body.should == "test=test"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "as a rack app" do
|
119
|
+
it "should respond with 404 when the path is not matched" do
|
120
|
+
get '/'
|
121
|
+
last_response.should be_not_found
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
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
|
+
|
10
|
+
Spec::Runner.configure do |config|
|
11
|
+
WebMock.disable_net_connect!
|
12
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-reverse-proxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Jon Swope
|
@@ -9,29 +14,59 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-11 00:00:00 -04:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: rack-test
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
version: "0"
|
17
42
|
type: :development
|
18
|
-
|
19
|
-
|
43
|
+
version_requirements: *id002
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: webmock
|
46
|
+
prerelease: false
|
47
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
20
48
|
requirements:
|
21
49
|
- - ">="
|
22
50
|
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 0
|
23
53
|
version: "0"
|
24
|
-
|
54
|
+
type: :development
|
55
|
+
version_requirements: *id003
|
25
56
|
- !ruby/object:Gem::Dependency
|
26
57
|
name: rack
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
30
60
|
requirements:
|
31
61
|
- - ">="
|
32
62
|
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 1
|
65
|
+
- 0
|
66
|
+
- 0
|
33
67
|
version: 1.0.0
|
34
|
-
|
68
|
+
type: :runtime
|
69
|
+
version_requirements: *id004
|
35
70
|
description: A Rack based reverse proxy for basic needs. Useful for testing or in cases where webserver configuration is unavailable.
|
36
71
|
email: jaswope@gmail.com
|
37
72
|
executables: []
|
@@ -51,8 +86,9 @@ files:
|
|
51
86
|
- VERSION
|
52
87
|
- lib/rack/reverse_proxy.rb
|
53
88
|
- rack-reverse-proxy.gemspec
|
54
|
-
-
|
55
|
-
-
|
89
|
+
- spec/rack/reverse_proxy_spec.rb
|
90
|
+
- spec/spec.opts
|
91
|
+
- spec/spec_helper.rb
|
56
92
|
- README
|
57
93
|
has_rdoc: true
|
58
94
|
homepage: http://github.com/jaswope/rack-reverse-proxy
|
@@ -67,21 +103,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
67
103
|
requirements:
|
68
104
|
- - ">="
|
69
105
|
- !ruby/object:Gem::Version
|
106
|
+
segments:
|
107
|
+
- 0
|
70
108
|
version: "0"
|
71
|
-
version:
|
72
109
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
110
|
requirements:
|
74
111
|
- - ">="
|
75
112
|
- !ruby/object:Gem::Version
|
113
|
+
segments:
|
114
|
+
- 0
|
76
115
|
version: "0"
|
77
|
-
version:
|
78
116
|
requirements: []
|
79
117
|
|
80
118
|
rubyforge_project:
|
81
|
-
rubygems_version: 1.3.
|
119
|
+
rubygems_version: 1.3.6
|
82
120
|
signing_key:
|
83
121
|
specification_version: 3
|
84
122
|
summary: A Simple Reverse Proxy for Rack
|
85
123
|
test_files:
|
86
|
-
-
|
87
|
-
-
|
124
|
+
- spec/spec_helper.rb
|
125
|
+
- spec/rack/reverse_proxy_spec.rb
|
data/test/helper.rb
DELETED