pretty_proxy 2.0.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pretty_proxy.rb +64 -58
- data/spec/pretty_proxy_spec.rb +13 -9
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ba185c1e9ef80173adf3ed23ad9b0ec056e305e
|
4
|
+
data.tar.gz: 4af0397bcdcaa6cd5baa7a2ea664e1ba1e734449
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3f0e0c339617821d7122b1cfe8784e34f17b1f4c70e628c0f670061b71b8ba900cf32c7a202fe26b998b26b182312c50001810f36378b7456e73dec5db0ff74
|
7
|
+
data.tar.gz: da92cb376d0975d95faf9ab262b24405ebd2156da6d4a0170ab693e2d73247c7d7b2eafd1482005eb24d88b037e368966e2ef02cf3841334493c390a2f63a4a5
|
data/lib/pretty_proxy.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
require 'uri'
|
3
2
|
require 'nokogiri'
|
4
3
|
require 'rack'
|
5
4
|
require 'rack-proxy'
|
5
|
+
require 'addressable/uri'
|
6
|
+
require 'uri'
|
6
7
|
|
7
8
|
# The PrettyProxy class aggregate and validate the configuration of a
|
8
9
|
# proxy based in simple pretty url oriented rewriting rules. It's too
|
@@ -47,9 +48,18 @@ require 'rack-proxy'
|
|
47
48
|
# the proxy_path and is followed by a original_path.
|
48
49
|
#
|
49
50
|
# 'in(side)/out(side) the proxy control': The url have (or not) the path
|
50
|
-
# starting with a original_path and the scheme, port and host are the
|
51
|
+
# starting with a original_path, and the scheme, port and host are the
|
51
52
|
# same of the original_domain.
|
52
53
|
#
|
54
|
+
# CHANGELOG:
|
55
|
+
# 3.0.0
|
56
|
+
# * return a String for unproxify_url (and not more a URI)
|
57
|
+
# because this is a change in the API (and can break code) the major
|
58
|
+
# version is now 3, if you don't use this method you can safely upgrade
|
59
|
+
# * depends in addressable gem
|
60
|
+
# * handles correctly the URIs without scheme (but with host)
|
61
|
+
# like '//duckduckgo.com/' (spec added for that)
|
62
|
+
#
|
53
63
|
# @author Henrique Becker
|
54
64
|
class PrettyProxy < Rack::Proxy
|
55
65
|
# The supertype of any exceptions explicitly raised by the methods
|
@@ -83,7 +93,7 @@ class PrettyProxy < Rack::Proxy
|
|
83
93
|
Utils.validate_original_domain_and_paths(original_domain, original_paths)
|
84
94
|
|
85
95
|
@proxy_path = proxy_path.clone
|
86
|
-
@original_domain = URI(original_domain.clone)
|
96
|
+
@original_domain = Addressable::URI.parse(original_domain.clone)
|
87
97
|
@original_paths = Set.new
|
88
98
|
if original_paths.respond_to? :each
|
89
99
|
original_paths.each { | value | @original_paths << value.clone }
|
@@ -121,29 +131,21 @@ class PrettyProxy < Rack::Proxy
|
|
121
131
|
# Take a proxy url and return the original URL behind the proxy. Preserve the
|
122
132
|
# query and fragment, if any. For the rewrite of a request @see rewrite_env.
|
123
133
|
# @param url [String, URI::HTTP, URI::HTTPS] A URL.
|
124
|
-
# @return [
|
134
|
+
# @return [String] The unproxified URI in a string.
|
125
135
|
# @raise PrettyProxy::ProxyError
|
126
136
|
def unproxify_url(url)
|
127
|
-
url = URI(url.clone)
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
url.path = url.path.slice((proxy_path.size-1)..-1)
|
132
|
-
unless original_paths.any? { | path | url.path.start_with? path }
|
133
|
-
fail ProxyError, "the proxy only responds to paths in the original_paths (#{@original_paths})"
|
134
|
-
end
|
135
|
-
if url.host == original_domain.host && url.path.start_with?(@proxy_path)
|
136
|
-
fail ProxyError, 'this is a request for the proxy for a proxy page (recursive request)'
|
137
|
+
url = Addressable::URI.parse(url.clone)
|
138
|
+
|
139
|
+
unless valid_path_for_proxy? url.path
|
140
|
+
fail ProxyError, "'#{url.to_s}' isn't inside the proxy control, it can't be unproxified"
|
137
141
|
end
|
138
|
-
url.host = original_domain.host
|
139
|
-
url.scheme = original_domain.scheme
|
140
|
-
url.port = original_domain.port
|
141
142
|
|
142
|
-
url
|
143
|
-
|
143
|
+
url.site = @original_domain.site
|
144
|
+
url.path = url.path.slice((@proxy_path.size-1)..-1)
|
145
|
+
|
146
|
+
url.to_s
|
147
|
+
rescue Addressable::URI::InvalidURIError
|
144
148
|
raise ArgumentError, "the url argument isn't a valid uri"
|
145
|
-
rescue URI::Error => e
|
146
|
-
raise ProxyError, "an unexpected URI exception has been thrown, the message is '#{e.message}'"
|
147
149
|
end
|
148
150
|
|
149
151
|
# Take a hyperlink and the url of the proxy page (not the original page)
|
@@ -158,34 +160,38 @@ class PrettyProxy < Rack::Proxy
|
|
158
160
|
# @return [String] A relative path or an url.
|
159
161
|
# @raise PrettyProxy::ProxyError
|
160
162
|
def proxify_hyperlink(hyperlink, proxy_page_url)
|
161
|
-
hyperlink = URI(hyperlink.clone)
|
162
|
-
proxy_page_url = URI(proxy_page_url)
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
# recreate the original site url from the relative/absolute path
|
171
|
-
absolute_link = unproxify_url proxy_page_url
|
172
|
-
absolute_link.path = Pathname.new(absolute_link.path).join(hyperlink.path).to_s
|
173
|
-
if inside_proxy_control? absolute_link
|
163
|
+
hyperlink = Addressable::URI.parse(hyperlink.clone)
|
164
|
+
proxy_page_url = Addressable::URI.parse(proxy_page_url)
|
165
|
+
|
166
|
+
# this is URI relative ('//duckduckgo.com', '/path', '../path')
|
167
|
+
if hyperlink.relative?
|
168
|
+
absolute_hyperlink = Addressable::URI.parse(unproxify_url(proxy_page_url))
|
169
|
+
.join(hyperlink)
|
170
|
+
if inside_proxy_control? absolute_hyperlink
|
171
|
+
# this is path relative ('../path', 'path', but not '//duckduckgo.com' or '/path')
|
174
172
|
if Pathname.new(hyperlink.path).relative?
|
175
|
-
if
|
176
|
-
valid_path_for_proxy?(absolute_link.path)
|
173
|
+
if point_to_a_proxy_page?(absolute_hyperlink, proxy_page_url)
|
177
174
|
# in the case of a relative path in the original page who points
|
178
175
|
# to a proxy page, and the proxy page is inside the proxy control
|
179
|
-
# we have to use the
|
180
|
-
#
|
181
|
-
# original_path as '/' is http://example.com/proxy/proxy/content
|
182
|
-
hyperlink =
|
176
|
+
# we have to use the absolute_hyperlink or the page will be double
|
177
|
+
# proxified. Example: ../proxy/content in http://example.com/proxy/content,
|
178
|
+
# with original_path as '/' is http://example.com/proxy/proxy/content
|
179
|
+
hyperlink = absolute_hyperlink
|
183
180
|
end
|
184
|
-
else
|
185
|
-
hyperlink.path = @proxy_path +
|
181
|
+
else
|
182
|
+
hyperlink.path = @proxy_path[0..-2] + absolute_hyperlink.path
|
183
|
+
hyperlink.host = proxy_page_url.host if hyperlink.host
|
184
|
+
hyperlink.port = proxy_page_url.port if hyperlink.port
|
186
185
|
end
|
187
186
|
else
|
188
|
-
hyperlink =
|
187
|
+
hyperlink = absolute_hyperlink
|
188
|
+
end
|
189
|
+
else # the hyperlink is absolute
|
190
|
+
if inside_proxy_control? hyperlink
|
191
|
+
# if points to the proxy itself we don't double-proxify
|
192
|
+
unless point_to_a_proxy_page?(hyperlink, proxy_page_url)
|
193
|
+
hyperlink = proxify_uri(hyperlink, proxy_page_url)
|
194
|
+
end
|
189
195
|
end
|
190
196
|
end
|
191
197
|
|
@@ -238,7 +244,8 @@ class PrettyProxy < Rack::Proxy
|
|
238
244
|
def rewrite_env(env)
|
239
245
|
env = env.clone
|
240
246
|
url_requested_to_proxy = Rack::Request.new(env).url
|
241
|
-
|
247
|
+
# Using URI, and not Addressable::URI because the port value is incorrect in the last
|
248
|
+
unproxified_url = URI(unproxify_url(url_requested_to_proxy))
|
242
249
|
|
243
250
|
if env['HTTP_HOST']
|
244
251
|
env['HTTP_HOST'] = unproxified_url.host
|
@@ -402,12 +409,10 @@ class PrettyProxy < Rack::Proxy
|
|
402
409
|
end
|
403
410
|
|
404
411
|
# api private Don't use this method.
|
405
|
-
def proxify_uri(
|
406
|
-
uri =
|
412
|
+
def proxify_uri(absolute_uri, proxy_site)
|
413
|
+
uri = absolute_uri.clone
|
407
414
|
|
408
|
-
uri.
|
409
|
-
uri.host = proxy_domain.host
|
410
|
-
uri.port = proxy_domain.port
|
415
|
+
uri.site = proxy_site.site
|
411
416
|
uri.path = @proxy_path + uri.path[1..-1]
|
412
417
|
|
413
418
|
uri
|
@@ -416,6 +421,7 @@ class PrettyProxy < Rack::Proxy
|
|
416
421
|
|
417
422
|
# api private Don't use the methods of this class. They are for internal use only.
|
418
423
|
module Utils
|
424
|
+
# TODO: check if isn't the case of change this for 'u1.site == u2.site'
|
419
425
|
def self.same_domain?(u1, u2)
|
420
426
|
u1.scheme == u2.scheme &&
|
421
427
|
u1.host == u2.host &&
|
@@ -437,23 +443,23 @@ class PrettyProxy < Rack::Proxy
|
|
437
443
|
def self.validate_original_domain_and_paths(original_domain, original_paths)
|
438
444
|
fail ConfigError, 'original_paths is empty' if original_paths.empty?
|
439
445
|
|
440
|
-
original_domain = URI(original_domain)
|
446
|
+
original_domain = Addressable::URI.parse(original_domain)
|
441
447
|
fail ConfigError, 'the original_domain has to have no query or fragment' if original_domain.query || original_domain.fragment
|
442
448
|
|
443
|
-
# can raise
|
449
|
+
# can raise errors
|
444
450
|
test_uri = original_domain.clone
|
445
451
|
if original_paths.respond_to?(:each)
|
446
|
-
original_paths.each
|
452
|
+
original_paths.each do | path |
|
453
|
+
fail ConfigError, "original_paths value '#{path}' don't start with a '/'" unless path.start_with? '/'
|
454
|
+
test_uri.path = path
|
455
|
+
end
|
447
456
|
else
|
457
|
+
fail ConfigError, "original_paths value '#{original_paths}' don't start with a '/'" unless original_paths.start_with? '/'
|
448
458
|
test_uri.path = original_paths
|
449
459
|
end
|
450
460
|
|
451
|
-
rescue URI::
|
452
|
-
raise ConfigError, "the
|
453
|
-
rescue URI::InvalidURIError => e
|
454
|
-
raise ConfigError, "the original_domain isn't a valid URI, message of the URI exception: '#{e.message}'"
|
455
|
-
rescue URI::Error => e
|
456
|
-
raise ConfigError, "a unexpected URI::Error exception was raised, message of the exception: '#{e.message}'"
|
461
|
+
rescue Addressable::URI::InvalidURIError => e
|
462
|
+
raise ConfigError, "the message of the URI exception: '#{e.message}'"
|
457
463
|
end
|
458
464
|
end
|
459
465
|
|
data/spec/pretty_proxy_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'pretty_proxy'
|
2
2
|
require 'equivalent-xml' # needed for be_equivalent_to xml rspec matcher
|
3
3
|
require 'zlib'
|
4
|
+
require 'uri'
|
4
5
|
|
5
6
|
shared_examples 'an reader method who encapsulate a mutable variable' do
|
6
7
|
context 'when the return is changed' do
|
@@ -94,7 +95,7 @@ describe PrettyProxy do
|
|
94
95
|
end
|
95
96
|
|
96
97
|
context 'when the original_domain is invalid' do
|
97
|
-
it { expect {new.call(right_args[0], 'http
|
98
|
+
it { expect {new.call(right_args[0], 'http://<invalid>.com', right_args[2])}.to raise_error(PrettyProxy::ConfigError)}
|
98
99
|
end
|
99
100
|
|
100
101
|
context 'when the original_domain has a query' do
|
@@ -127,7 +128,7 @@ describe PrettyProxy do
|
|
127
128
|
|
128
129
|
# NOTE: excessive metaprogramming? only save 3~6 lines
|
129
130
|
[ [ :proxy_path=, "when proxy_path doesn't end with a '/'", '/proxy'],
|
130
|
-
[ :original_domain=, 'when the original_domain is invalid', 'http
|
131
|
+
[ :original_domain=, 'when the original_domain is invalid', 'http://<invalid>.com'],
|
131
132
|
[ :original_paths=, "when the original_paths don't begin with a '/'", 'content']
|
132
133
|
].each do | error_case |
|
133
134
|
writter, context_desc, invalid_input = *error_case
|
@@ -144,31 +145,31 @@ describe PrettyProxy do
|
|
144
145
|
|
145
146
|
context 'when the original_path has no trailing slash' do
|
146
147
|
it 'allow no trailing slash in the url' do
|
147
|
-
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1')).to eq
|
148
|
+
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1')).to eq 'http://site.net/p1'
|
148
149
|
end
|
149
150
|
it 'allow trailing slash in the url' do
|
150
|
-
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1/')).to eq
|
151
|
+
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1/')).to eq 'http://site.net/p1/'
|
151
152
|
end
|
152
153
|
end
|
153
154
|
context 'when the original_path has a trailing slash' do
|
154
155
|
it 'allow trailing slash in the url' do
|
155
|
-
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p2/p2_2/')).to eq
|
156
|
+
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p2/p2_2/')).to eq 'http://site.net/p2/p2_2/'
|
156
157
|
end
|
157
158
|
it "don't allow no trailing slash" do
|
158
159
|
expect { pp.unproxify_url('http://myproxy.net/proxys/sitez/p2/p2_2') }.to raise_error(PrettyProxy::ProxyError)
|
159
160
|
end
|
160
161
|
end
|
161
162
|
it 'allow subdirectories inside that path' do
|
162
|
-
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1/a/b/c/')).to eq
|
163
|
+
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1/a/b/c/')).to eq 'http://site.net/p1/a/b/c/'
|
163
164
|
end
|
164
165
|
it 'preserve querys in the url' do
|
165
|
-
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1/?q=error&l=pt')).to eq
|
166
|
+
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1/?q=error&l=pt')).to eq 'http://site.net/p1/?q=error&l=pt'
|
166
167
|
end
|
167
168
|
it 'preserve fragments in the url' do
|
168
|
-
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1/#id')).to eq
|
169
|
+
expect(pp.unproxify_url('http://myproxy.net/proxys/sitez/p1/#id')).to eq 'http://site.net/p1/#id'
|
169
170
|
end
|
170
171
|
it 'change the port to the original' do
|
171
|
-
expect(pp.unproxify_url('http://myproxy.net:9292/proxys/sitez/p1/#id').port).to eq 80
|
172
|
+
expect(URI(pp.unproxify_url('http://myproxy.net:9292/proxys/sitez/p1/#id')).port).to eq 80
|
172
173
|
end
|
173
174
|
|
174
175
|
context 'when the url redirect to the own proxy' do
|
@@ -193,6 +194,9 @@ describe PrettyProxy do
|
|
193
194
|
it "proxify hyperlinks with scheme to inside the proxy control" do
|
194
195
|
expect(pp.proxify_hyperlink('http://site.net/p2/p2_2/', 'http://theproxy.net/proxy/p1')).to eq 'http://theproxy.net/proxy/p2/p2_2/'
|
195
196
|
end
|
197
|
+
it "proxify hyperlinks without scheme to inside the proxy control" do
|
198
|
+
expect(pp.proxify_hyperlink('//site.net/p2/p2_2/', 'http://theproxy.net/proxy/p1')).to eq '//theproxy.net/proxy/p2/p2_2/'
|
199
|
+
end
|
196
200
|
it "don't change hyperlinks with scheme to ouside the proxy control" do
|
197
201
|
expect(pp.proxify_hyperlink('http://othersite.net', 'http://theproxy.net/proxy/p1')).to eq 'http://othersite.net'
|
198
202
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pretty_proxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henrique Becker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: addressable
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.3'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.3'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: equivalent-xml
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|