pretty_proxy 2.0.1 → 3.0.0
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 +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
|