Compare commits

..

10 Commits

Author SHA1 Message Date
Nigel Brookes-Thomas 848d5e6714 Merge branch 'master' of github.com:BillyRuffian/roda-proxy 2020-03-26 11:36:45 +00:00
Nigel Brookes-Thomas efcc6585a6 we don't support chunked transfer encoding, strip that from the response headeers 2020-03-26 11:36:27 +00:00
Nigel Brookes-Thomas b77cf2e3bc
Update README.md 2020-03-25 12:33:29 +00:00
Nigel Brookes-Thomas 232ad0a2ba
Update README.md 2020-03-25 12:32:42 +00:00
Nigel Brookes-Thomas 4924955c6c rogue breadcrumb 2020-03-13 17:20:22 +00:00
Nigel Brookes-Thomas 26be6fb9bb doh 2020-03-13 16:49:26 +00:00
Nigel Brookes-Thomas 2cfa847f6f path prefix is now actually a prefix 2020-03-13 12:04:07 +00:00
Nigel Brookes-Thomas f8ee7b2e91 conditional checking was arse backwards 2020-03-13 11:33:40 +00:00
Nigel Brookes-Thomas 85c863deab setting the via header in both directions 2020-03-13 10:47:21 +00:00
Nigel Brookes-Thomas cc024e55a5 updated gemspec 2020-03-13 09:51:04 +00:00
4 changed files with 36 additions and 17 deletions

View File

@ -58,7 +58,7 @@ route do |r|
end end
``` ```
The proxy will always be invoked. Headers and body are passed through unmodified in both directions with the exception of `Host` which is rewritten to match the target. The proxy will always be invoked. Headers and body are passed through unmodified in both directions with the exception of `Host` which is rewritten to match the target and `Via` which is created (or appended to if it already exists) to indicate the proxy path.
Also provided is a conditional proxy: Also provided is a conditional proxy:
@ -82,7 +82,7 @@ route do |r|
end end
``` ```
With `proxy_when` the first optional parameter expects a truthy value or a block / lambda that returns a truthy value. This must be equivalent to `true` for the proxying to occur. The optional probability is a float between 0 and 1 indicating the probability that proxying will happen. Both paramters can be used alone or in isolation. With `proxy_when` the first optional parameter expects a truthy value or a block / lambda that returns a truthy value. This must be equivalent to `true` for the proxying to occur. The optional probability is a float between 0 and 1 indicating the probability that proxying will happen. Both parameters can be used alone or in isolation.
If and only if proxying does not occur will the block be evaluated and return to Roda for rendering. If and only if proxying does not occur will the block be evaluated and return to Roda for rendering.

View File

@ -13,13 +13,17 @@ class Roda
# Respond to the configure method to set the destination when proxying # Respond to the configure method to set the destination when proxying
# Expects the following options: # Expects the following options:
# [to] Required. The scheme and host of the proxy. Should not end with a slash. # [to] Required. The scheme and host of the proxy. Should not end with a slash.
# [path] Optional. The path to append to the above for proxying. # [path_prefix] Optional. The path to append to the above for proxying.
# Should begin with a +/+. Defaults to +/+. # The current request path will be prefixed on to this value.
# Should begin and end with a +/+. Defaults to +/+.
# For example, if the path prefix is +/foo/+ and the request received
# by Roda is +GET /postcode/lookup+, The proxied request will be dispatched
# to +GET /home/postcode/lookup+
# Example: # Example:
# plugin :proxy, to: 'https://foo.bar', path: '/my/api' # plugin :proxy, to: 'https://foo.bar', path: '/my/api'
def self.configure(app, opts = {}) def self.configure(app, opts = {})
app.opts[:proxy_to] = opts.fetch(:to, nil) app.opts[:proxy_to] = opts.fetch(:to, nil)
app.opts[:proxy_path] = opts.fetch(:path, '/') app.opts[:proxy_path] = opts.fetch(:path_prefix, '/')
raise 'Proxy host not set, use "plugin :proxy, to: http://example.com"' unless app.opts[:proxy_to] raise 'Proxy host not set, use "plugin :proxy, to: http://example.com"' unless app.opts[:proxy_to]
end end
@ -33,6 +37,7 @@ class Roda
def proxy def proxy
method = Faraday.method(env['REQUEST_METHOD'].downcase.to_sym) method = Faraday.method(env['REQUEST_METHOD'].downcase.to_sym)
f_response = method.call(_proxy_url) { |req| _proxy_request(req) } f_response = method.call(_proxy_url) { |req| _proxy_request(req) }
# p f_response
_respond(f_response) _respond(f_response)
end end
@ -50,17 +55,19 @@ class Roda
shall_proxy = Random.rand(0.0..1.0) <= probability shall_proxy = Random.rand(0.0..1.0) <= probability
if shall_proxy && ( condition.respond_to?(:call) ? condition.call : condition ) if shall_proxy && ( condition.respond_to?(:call) ? condition.call : condition )
yield(self)
else
proxy proxy
else
yield(self)
end end
end end
private private
def _proxy_url def _proxy_url
@_proxy_url ||= URI(roda_class.opts[:proxy_to]) @_proxy_url ||= URI(roda_class.opts[:proxy_to])
.then { |uri| uri.path = roda_class.opts[:proxy_path]; uri } .then { |uri| uri.path = roda_class.opts[:proxy_path]; uri } # prefix
.then { |uri| uri.path += env['PATH_INFO'][1..-1]; uri } # path
.then { |uri| uri.query = env['QUERY_STRING']; uri } .then { |uri| uri.query = env['QUERY_STRING']; uri }
end end
@ -73,7 +80,11 @@ class Roda
.split('_') .split('_')
.map(&:capitalize) .map(&:capitalize)
.join('-') .join('-')
end.merge({ 'Host' => "#{_proxy_url.host}:#{_proxy_url.port}" }) end
.merge({
'Host' => "#{_proxy_url.host}:#{_proxy_url.port}",
'Via' => _via_header_string
})
end end
def _proxy_request(req) def _proxy_request(req)
@ -82,9 +93,17 @@ class Roda
def _respond(proxied_response) def _respond(proxied_response)
response.status = proxied_response.status response.status = proxied_response.status
proxied_response.headers.each { |k, v| response[k] = v } proxied_response
.headers
.reject { |k, v| k.downcase == 'transfer-encoding' }
.each { |k, v| response[k] = v }
response['Via'] = _via_header_string
response.write(proxied_response.body) response.write(proxied_response.body)
end end
def _via_header_string
"#{env['SERVER_PROTOCOL']} #{env['SERVER_NAME']}:#{env['SERVER_PORT']}"
end
end end
end end

View File

@ -2,6 +2,6 @@
class Roda class Roda
module Proxy module Proxy
VERSION = '0.1.0' VERSION = '1.0.5'
end end
end end

View File

@ -8,17 +8,17 @@ Gem::Specification.new do |spec|
spec.authors = ['Nigel Brookes-Thomas'] spec.authors = ['Nigel Brookes-Thomas']
spec.email = ['nigel@brookes-thomas.co.uk'] spec.email = ['nigel@brookes-thomas.co.uk']
spec.summary = 'Proxy service for Roda' spec.summary = 'Reverse proxy plugin for Roda'
spec.description = 'Roda proxy service' spec.description = 'A very simple reverse proxy for Roda'
spec.homepage = 'http://foo.bar' spec.homepage = 'https://github.com/BillyRuffian/roda-proxy'
spec.license = 'MIT' spec.license = 'MIT'
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0') spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" spec.metadata['allowed_push_host'] = 'https://rubygems.org'
spec.metadata['homepage_uri'] = spec.homepage spec.metadata['homepage_uri'] = spec.homepage
spec.metadata['source_code_uri'] = 'http://foo.bar' spec.metadata['source_code_uri'] = 'https://github.com/BillyRuffian/roda-proxy'
spec.metadata['changelog_uri'] = 'http://foo.bar' spec.metadata['changelog_uri'] = 'https://github.com/BillyRuffian/roda-proxy'
# Specify which files should be added to the gem when it is released. # Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git. # The `git ls-files -z` loads the files in the RubyGem that have been added into git.