rrproxy 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rrproxy.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Caleb Spare
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ rrproxy
2
+ =======
3
+
4
+ rrproxy ("routing reverse proxy" or "rockin' ruby proxy" -- you pick) is a very simple reverse proxy server
5
+ that can route requests to different servers based on simple pattern-matching rules against the requests. It
6
+ is intended for use in a development environment as a substitute for 'real' proxies (nginx/HAProxy/whatever)
7
+ that you use in production.
8
+
9
+ Installation
10
+ ------------
11
+
12
+ $ gem install rrproxy
13
+
14
+ rrproxy requires Ruby 1.9 (because it's based on Goliath).
15
+
16
+ Usage
17
+ -----
18
+
19
+ rrproxy takes a very simple Ruby configuration file.
20
+
21
+ [
22
+ ["/styles/screen.css", "localhost:8000"],
23
+ ["", "example.com"]
24
+ ]
25
+
26
+ As you can probably guess, this will redirect requests for example.com's css file to a local server (while
27
+ passing all other requests through normally).
28
+
29
+ Here's a more complicated example (it's also in `examples/example_config.rb`):
30
+
31
+ [
32
+ ["/foo/bar?special=true", "localhost:1234"], # Route this specific request to a local server
33
+ [%r{^(/foo).*}, "google.com", ""], # You can use a regex, and also replace the match with a third arg
34
+ ["", "amazon.com"] # Empty string matches everything
35
+ ]
36
+
37
+ You will provide an array of tuples, where each one is of the form
38
+
39
+ [pattern, target_host, <optional replacement string>]
40
+
41
+ For each request, rrproxy will examine each routing rule in order, checking for a prefix match (if the pattern
42
+ is a string) or a regex match. The first match found will be used, and the host for the request will be
43
+ changed to the corresponding target host. If a replacement is provided, it will be used as a substitute for
44
+ the first regex matching group (if the pattern is a regex) or the whole pattern (if the pattern is a string).
45
+
46
+ Credits
47
+ -------
48
+
49
+ * @tobert for the idea to use Goliath
50
+ * The PostRank folks for a kickass server framework
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/bin/rrproxy ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "trollop"
4
+ require "dedent"
5
+ require "colorize"
6
+
7
+ require "rrproxy"
8
+
9
+ # The goliath folks really need to take a page out of Sinatra's book and provide an easy way to start up a
10
+ # server manually without using all their application runner and option parsing shit (in Sinatra terms,
11
+ # 'sinatra' vs 'sinatra/base'). As it is I had to poke around the source code a while to figure out all the
12
+ # little things necessary to make it work.
13
+
14
+ # See https://github.com/postrank-labs/goliath/blob/master/lib/goliath/runner.rb
15
+ def create_logger
16
+ logger = Log4r::Logger.new("rrproxy")
17
+ log_format = Log4r::PatternFormatter.new(:pattern => "[%d : %l] %m")
18
+ logger.add(Log4r::StdoutOutputter.new("console", :formatter => log_format))
19
+ logger.level = Log4r::INFO
20
+ logger
21
+ end
22
+
23
+ options = Trollop.options do
24
+ banner <<-EOS.dedent
25
+ rrproxy is a very simple reverse http proxy that can route requests based on pattern-matching the
26
+ URI. The configuration file is Ruby, and it must have the following form:
27
+
28
+ [
29
+ ["/foo/bar?special=true", "localhost:1234"], # Route this specific request to a local server
30
+ [%r{^(/foo).*}, "google.com", ""], # You can use a regex, and also replace the match
31
+ ["", "amazon.com"] # Empty string matches everything
32
+ ]
33
+
34
+ Usage:
35
+
36
+ $ rrproxy [options] CONFIG_FILE
37
+
38
+ where [options] are:
39
+ EOS
40
+ opt :address, "Bind address", :default => "0.0.0.0"
41
+ opt :port, "Port", :default => 9876
42
+ end
43
+
44
+ Trollop.die "You must provide a configuration file" unless ARGV[0]
45
+ Trollop.die "Invalid config file: #{ARGV[0]}" unless File.file? ARGV[0]
46
+ begin
47
+ RRProxy.routes = eval(File.read(ARGV[0]))
48
+ rescue
49
+ Trollop.die "Error reading or parsing the config file #{ARGV[0]}"
50
+ end
51
+
52
+ logger = create_logger
53
+ logger.info "Starting rrproxy (powered by Goliath) on #{options[:address]}:#{options[:port]}".green
54
+ RRProxy.routes.each do |route|
55
+ pattern, target, replacement = route
56
+ message = "Proxying `#{pattern}` to #{target}"
57
+ message << " and replacing pattern matches with `#{replacement}`" if replacement
58
+ logger.info message.green
59
+ end
60
+
61
+ Goliath.env = :development
62
+ api = RRProxy.new
63
+ server = Goliath::Server.new(options[:address], options[:port])
64
+ server.logger = logger
65
+ server.api = api
66
+ server.app = Goliath::Rack::Builder.build(RRProxy, api)
67
+ server.plugins = []
68
+ server.start
@@ -0,0 +1,8 @@
1
+ # General form: An array of
2
+ # [pattern, target_host, <optional replacement string>]
3
+
4
+ [
5
+ ["/foo/bar?special=true", "localhost:1234"], # Route this specific request to a local server
6
+ [%r{^(/foo).*}, "google.com", ""], # You can use a regex, and also replace the match with a third arg
7
+ ["", "amazon.com"] # Empty string matches everything
8
+ ]
data/lib/rrproxy.rb ADDED
@@ -0,0 +1,54 @@
1
+ require "goliath/api"
2
+ require "goliath/goliath"
3
+ require "goliath/rack"
4
+ require "goliath/server"
5
+ require "log4r"
6
+ require "em-synchrony/em-http"
7
+
8
+ class RRProxy < Goliath::API
9
+ class << self
10
+ attr_accessor :routes
11
+ end
12
+
13
+ use Goliath::Rack::Params
14
+
15
+ def options_parser(option_parser, options)
16
+ option_parser.on("-c", "--config CONFIG_FILE", "Ruby routes configuration file") do |filename|
17
+ options[:config] = filename
18
+ end
19
+ abort "asdf" unless File.file?(options[:config])
20
+ end
21
+
22
+ def on_headers(env, headers) env["untampered_headers"] = headers end
23
+
24
+ def response(env)
25
+ uri = env["REQUEST_URI"]
26
+ method = env["REQUEST_METHOD"]
27
+ logger.info "Proxying #{method} #{uri}"
28
+ method = method.downcase.to_sym
29
+ RRProxy.routes.each do |pattern, target, replacement|
30
+ if pattern.is_a?(Regexp)
31
+ next unless uri =~ pattern
32
+ uri.sub!($1, replacement) if replacement
33
+ else
34
+ next unless uri.start_with? pattern
35
+ uri.sub!(pattern, replacement) if replacement
36
+ end
37
+
38
+ target_url = "http://#{target}#{uri}"
39
+ headers = env["untampered_headers"]
40
+ headers["HOST"] = target
41
+ params = { :head => headers }
42
+ params[:body] = env["params"] if [:put, :post, :patch].include? method
43
+
44
+ http = EM::HttpRequest.new(target_url).send(method, params)
45
+ response_headers = {}
46
+ http.response_header.each do |k, v|
47
+ response_headers[k.downcase.split("_").map(&:capitalize).join("-")] = v
48
+ end
49
+
50
+ return [http.response_header.status, response_headers, [http.response]]
51
+ end
52
+ [503, {}, "No target specified for this path."]
53
+ end
54
+ end
data/rrproxy.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.authors = ["Caleb Spare"]
3
+ gem.email = ["cespare@gmail.com"]
4
+ gem.description = %q{rrproxy is a very simple routing reverse proxy written in Ruby.}
5
+ gem.summary = %q{A routing reverse proxy.}
6
+ gem.homepage = ""
7
+
8
+ gem.files = `git ls-files`.split($\)
9
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
10
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
11
+ gem.name = "rrproxy"
12
+ gem.version = "0.0.1"
13
+ gem.require_paths = ["lib"]
14
+
15
+ gem.add_dependency "goliath"
16
+ gem.add_dependency "log4r"
17
+ gem.add_dependency "em-http-request"
18
+ gem.add_dependency "trollop"
19
+ gem.add_dependency "dedent"
20
+ gem.add_dependency "colorize"
21
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rrproxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Caleb Spare
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-16 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: goliath
16
+ requirement: &24235400 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *24235400
25
+ - !ruby/object:Gem::Dependency
26
+ name: log4r
27
+ requirement: &24200780 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *24200780
36
+ - !ruby/object:Gem::Dependency
37
+ name: em-http-request
38
+ requirement: &24199760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *24199760
47
+ - !ruby/object:Gem::Dependency
48
+ name: trollop
49
+ requirement: &24197520 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *24197520
58
+ - !ruby/object:Gem::Dependency
59
+ name: dedent
60
+ requirement: &24196100 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *24196100
69
+ - !ruby/object:Gem::Dependency
70
+ name: colorize
71
+ requirement: &24194600 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *24194600
80
+ description: rrproxy is a very simple routing reverse proxy written in Ruby.
81
+ email:
82
+ - cespare@gmail.com
83
+ executables:
84
+ - rrproxy
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - .gitignore
89
+ - Gemfile
90
+ - LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - bin/rrproxy
94
+ - example/example_config.rb
95
+ - lib/rrproxy.rb
96
+ - rrproxy.gemspec
97
+ homepage: ''
98
+ licenses: []
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.10
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: A routing reverse proxy.
121
+ test_files: []