path_router 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 +6 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +22 -0
- data/README.md +67 -0
- data/Rakefile +1 -0
- data/bin/path_router +37 -0
- data/example_path_router.rb +17 -0
- data/lib/path_router/router.rb +46 -0
- data/lib/path_router/version.rb +3 -0
- data/lib/path_router.rb +2 -0
- data/path_router.gemspec +23 -0
- data/proxymachine_config.rb +18 -0
- data/spec/path_router_spec.rb +36 -0
- data/spec/spec_helper.rb +3 -0
- metadata +86 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
eventmachine (0.12.10)
|
6
|
+
proxymachine (1.2.4)
|
7
|
+
eventmachine (>= 0.12.10)
|
8
|
+
rspec (2.6.0)
|
9
|
+
rspec-core (~> 2.6.0)
|
10
|
+
rspec-expectations (~> 2.6.0)
|
11
|
+
rspec-mocks (~> 2.6.0)
|
12
|
+
rspec-core (2.6.4)
|
13
|
+
rspec-expectations (2.6.0)
|
14
|
+
diff-lcs (~> 1.1.2)
|
15
|
+
rspec-mocks (2.6.0)
|
16
|
+
|
17
|
+
PLATFORMS
|
18
|
+
ruby
|
19
|
+
|
20
|
+
DEPENDENCIES
|
21
|
+
proxymachine
|
22
|
+
rspec
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
path_router
|
2
|
+
===========
|
3
|
+
|
4
|
+
HTTP routing by URL path, built on the excellent [ProxyMachine](https://github.com/mojombo/proxymachine) by the GitHub guys.
|
5
|
+
|
6
|
+
GitHub uses ProxyMachine to service millions of git connections every day.
|
7
|
+
|
8
|
+
|
9
|
+
Install
|
10
|
+
-------
|
11
|
+
|
12
|
+
```
|
13
|
+
gem install path_router # installs path_router and proxymachine
|
14
|
+
path_router init # creates example path_router.rb
|
15
|
+
vim path_router.rb # specify your backends and URL patterns
|
16
|
+
path_router # fire it up, optionally with -h host and -p port
|
17
|
+
```
|
18
|
+
|
19
|
+
Routes
|
20
|
+
------
|
21
|
+
|
22
|
+
See `example_path_router.rb` to get the general idea.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
PathRouter::Router.instance.reset.tap do |r|
|
26
|
+
|
27
|
+
r.backends = {
|
28
|
+
rails: "127.0.0.1:3000", # default
|
29
|
+
static: "127.0.0.1:8080",
|
30
|
+
wordpress: "10.0.0.1:80",
|
31
|
+
}
|
32
|
+
|
33
|
+
r.connect :static,
|
34
|
+
%r{^/robots.txt},
|
35
|
+
%r{^/(?:images|stylesheets|javascripts)/}
|
36
|
+
|
37
|
+
r.connect :wordpress,
|
38
|
+
%r{^/blog/},
|
39
|
+
%r{^/feed}
|
40
|
+
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
The only non-obvious point is that the first backend in the hash is the default catch-all.
|
45
|
+
Ruby 1.8 users get random default backend; think of it as an easter egg ;)
|
46
|
+
|
47
|
+
|
48
|
+
Tests
|
49
|
+
-----
|
50
|
+
|
51
|
+
```
|
52
|
+
$ rspec spec/*_spec.rb
|
53
|
+
|
54
|
+
PathRouter::Router
|
55
|
+
routes by specified patterns
|
56
|
+
defaults to first backend for unmatched requests
|
57
|
+
|
58
|
+
Finished in 0.00056 seconds
|
59
|
+
2 examples, 0 failures
|
60
|
+
```
|
61
|
+
|
62
|
+
|
63
|
+
Meh.
|
64
|
+
----
|
65
|
+
|
66
|
+
(c) 2011 Paul Annesley, MIT licence.
|
67
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/path_router
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
BASEDIR = File.realpath(File.join(File.dirname(__FILE__), ".."))
|
6
|
+
|
7
|
+
if ARGV.include? "init"
|
8
|
+
require "fileutils"
|
9
|
+
dest = "./path_router.rb"
|
10
|
+
FileUtils.cp File.join(BASEDIR, "example_path_router.rb"), dest
|
11
|
+
puts "Created example #{dest}"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
|
15
|
+
args = [ "--config", File.join(BASEDIR, "proxymachine_config.rb") ]
|
16
|
+
|
17
|
+
OptionParser.new do |opts|
|
18
|
+
opts.banner = <<-EOF
|
19
|
+
|
20
|
+
path_router init
|
21
|
+
Creates example path_router.rb into the current directory.
|
22
|
+
|
23
|
+
path_router [-h <host>] [-p <port>]
|
24
|
+
Start ProxyMachine with path_router config loaded from path_router.rb in
|
25
|
+
the current directory.
|
26
|
+
|
27
|
+
Options:
|
28
|
+
EOF
|
29
|
+
opts.on("-hHOST", "--host HOST", "Hostname to bind. Default 0.0.0.0") do |host|
|
30
|
+
args += [ "--host", host ]
|
31
|
+
end
|
32
|
+
opts.on("-pPORT", "--port PORT", "Port to listen on. Default 5432") do |port|
|
33
|
+
args += [ "--port", port ]
|
34
|
+
end
|
35
|
+
end.parse!
|
36
|
+
|
37
|
+
exec "proxymachine", *args
|
@@ -0,0 +1,17 @@
|
|
1
|
+
PathRouter::Router.instance.reset.tap do |r|
|
2
|
+
|
3
|
+
r.backends = {
|
4
|
+
rails: "127.0.0.1:3000", # default
|
5
|
+
static: "127.0.0.1:8080",
|
6
|
+
wordpress: "10.0.0.1:80",
|
7
|
+
}
|
8
|
+
|
9
|
+
r.connect :static,
|
10
|
+
%r{^/robots.txt},
|
11
|
+
%r{^/(?:images|stylesheets|javascripts)/}
|
12
|
+
|
13
|
+
r.connect :wordpress,
|
14
|
+
%r{^/blog/},
|
15
|
+
%r{^/feed}
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module PathRouter
|
2
|
+
class Router
|
3
|
+
|
4
|
+
def self.instance
|
5
|
+
@instance ||= new
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
reset
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset
|
13
|
+
@backends = {}
|
14
|
+
@routes = {}
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_routes(file = "path_router.rb")
|
19
|
+
puts "Loading routes from #{file}"
|
20
|
+
load file
|
21
|
+
rescue LoadError => e
|
22
|
+
puts "Failed to load routes: " << e.message
|
23
|
+
end
|
24
|
+
|
25
|
+
# Hash of backends, { Regexp => "ip:port", ... }
|
26
|
+
def backends=(backends)
|
27
|
+
backends.default = backends.values.first
|
28
|
+
@backends = backends
|
29
|
+
end
|
30
|
+
|
31
|
+
# Connect patterns to the given backend.
|
32
|
+
def connect(backend, *patterns)
|
33
|
+
patterns.each { |p| @routes[p] = backend }
|
34
|
+
end
|
35
|
+
|
36
|
+
# method e.g. "GET", currently unused
|
37
|
+
# path e.g. "/some/path?including=query+string"
|
38
|
+
def lookup(method, path)
|
39
|
+
_, backend = @routes.detect do |pattern, _|
|
40
|
+
path =~ pattern
|
41
|
+
end
|
42
|
+
@backends[backend]
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
data/lib/path_router.rb
ADDED
data/path_router.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "path_router/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "path_router"
|
7
|
+
s.version = PathRouter::VERSION
|
8
|
+
s.authors = ["Paul Annesley"]
|
9
|
+
s.email = ["paul@annesley.cc"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{HTTP routing by URL path, built on ProxyMachine.}
|
12
|
+
s.description = %q{Easily route HTTP requests to different backends by pattern matching the URL path.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "path_router"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency "proxymachine", "~> 1.2.4"
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift "./lib"
|
2
|
+
require "path_router/router"
|
3
|
+
|
4
|
+
module PathRouter
|
5
|
+
|
6
|
+
Signal.trap("USR2") { Router.instance.load_routes }
|
7
|
+
|
8
|
+
Router.instance.load_routes
|
9
|
+
|
10
|
+
proxy do |data|
|
11
|
+
if data =~ %r{^(\w+) (\S+) HTTP/\d.\d\r\n}
|
12
|
+
{ remote: Router.instance.lookup($1, $2) }
|
13
|
+
else
|
14
|
+
{ noop: true }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
module PathRouter
|
4
|
+
describe Router do
|
5
|
+
|
6
|
+
let(:router) do
|
7
|
+
Router.new.tap do |r|
|
8
|
+
|
9
|
+
r.backends = {
|
10
|
+
rails: "127.0.0.1:3000",
|
11
|
+
static: "127.0.0.1:8080",
|
12
|
+
api: "api:80"
|
13
|
+
}
|
14
|
+
|
15
|
+
r.connect :static,
|
16
|
+
%r{^/robots.txt},
|
17
|
+
%r{^/(?:images|stylesheets|javascripts)/}
|
18
|
+
|
19
|
+
r.connect :api,
|
20
|
+
%r{^/api/}
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "routes by specified patterns" do
|
26
|
+
router.lookup("GET", "/robots.txt").should == "127.0.0.1:8080"
|
27
|
+
router.lookup("GET", "/images/logo.png").should == "127.0.0.1:8080"
|
28
|
+
router.lookup("GET", "/api/list").should == "api:80"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "defaults to first backend for unmatched requests" do
|
32
|
+
router.lookup("GET", "/anything/else").should == "127.0.0.1:3000"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: path_router
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Paul Annesley
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-06-17 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: proxymachine
|
16
|
+
requirement: &2169316300 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.2.4
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2169316300
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &2169315880 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2169315880
|
36
|
+
description: Easily route HTTP requests to different backends by pattern matching
|
37
|
+
the URL path.
|
38
|
+
email:
|
39
|
+
- paul@annesley.cc
|
40
|
+
executables:
|
41
|
+
- path_router
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- .rspec
|
47
|
+
- Gemfile
|
48
|
+
- Gemfile.lock
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- bin/path_router
|
52
|
+
- example_path_router.rb
|
53
|
+
- lib/path_router.rb
|
54
|
+
- lib/path_router/router.rb
|
55
|
+
- lib/path_router/version.rb
|
56
|
+
- path_router.gemspec
|
57
|
+
- proxymachine_config.rb
|
58
|
+
- spec/path_router_spec.rb
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
homepage: ''
|
61
|
+
licenses: []
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project: path_router
|
80
|
+
rubygems_version: 1.8.5
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: HTTP routing by URL path, built on ProxyMachine.
|
84
|
+
test_files:
|
85
|
+
- spec/path_router_spec.rb
|
86
|
+
- spec/spec_helper.rb
|