em-proxy 0.1.5 → 0.1.6
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/Gemfile.lock +19 -17
- data/README.md +67 -0
- data/Rakefile +8 -2
- data/em-proxy.gemspec +2 -2
- data/examples/balancing.rb +3 -1
- data/examples/http_proxy.rb +47 -0
- data/lib/em-proxy/backend.rb +1 -3
- data/lib/em-proxy/connection.rb +114 -114
- data/spec/balancing_spec.rb +2 -2
- data/spec/helper.rb +3 -4
- data/spec/proxy_spec.rb +2 -2
- metadata +54 -78
- data/README.rdoc +0 -82
data/Gemfile.lock
CHANGED
@@ -7,23 +7,26 @@ PATH
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
addressable (2.2.
|
11
|
-
ansi (1.
|
12
|
-
diff-lcs (1.1.
|
13
|
-
em-http-request (0.
|
14
|
-
addressable (>= 2.
|
15
|
-
|
16
|
-
eventmachine (>= 0.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
10
|
+
addressable (2.2.6)
|
11
|
+
ansi (1.4.0)
|
12
|
+
diff-lcs (1.1.3)
|
13
|
+
em-http-request (1.0.0)
|
14
|
+
addressable (>= 2.2.3)
|
15
|
+
em-socksify
|
16
|
+
eventmachine (>= 1.0.0.beta.3)
|
17
|
+
http_parser.rb (>= 0.5.2)
|
18
|
+
em-socksify (0.1.0)
|
19
|
+
eventmachine
|
20
|
+
eventmachine (1.0.0.beta.4)
|
21
|
+
http_parser.rb (0.5.3)
|
22
|
+
rspec (2.7.0)
|
23
|
+
rspec-core (~> 2.7.0)
|
24
|
+
rspec-expectations (~> 2.7.0)
|
25
|
+
rspec-mocks (~> 2.7.0)
|
26
|
+
rspec-core (2.7.1)
|
27
|
+
rspec-expectations (2.7.0)
|
25
28
|
diff-lcs (~> 1.1.2)
|
26
|
-
rspec-mocks (2.
|
29
|
+
rspec-mocks (2.7.0)
|
27
30
|
|
28
31
|
PLATFORMS
|
29
32
|
ruby
|
@@ -32,5 +35,4 @@ DEPENDENCIES
|
|
32
35
|
ansi
|
33
36
|
em-http-request
|
34
37
|
em-proxy!
|
35
|
-
eventmachine
|
36
38
|
rspec
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# EM-Proxy
|
2
|
+
|
3
|
+
EventMachine Proxy DSL for writing high-performance transparent / intercepting proxies in Ruby.
|
4
|
+
|
5
|
+
- EngineYard tutorial: [Load testing your environment using em-proxy](http://docs.engineyard.com/em-proxy.html)
|
6
|
+
- [Slides from RailsConf 2009](http://bit.ly/D7oWB)
|
7
|
+
- [GoGaRuCo notes & Slides](http://www.igvita.com/2009/04/20/ruby-proxies-for-scale-and-monitoring/)
|
8
|
+
|
9
|
+
## Getting started
|
10
|
+
|
11
|
+
$> gem install em-proxy
|
12
|
+
$> em-proxy
|
13
|
+
Usage: em-proxy [options]
|
14
|
+
-l, --listen [PORT] Port to listen on
|
15
|
+
-d, --duplex [host:port, ...] List of backends to duplex data to
|
16
|
+
-r, --relay [hostname:port] Relay endpoint: hostname:port
|
17
|
+
-v, --verbose Run in debug mode
|
18
|
+
|
19
|
+
$> em-proxy -l 8080 -r localhost:8081 -d localhost:8082,localhost:8083 -v
|
20
|
+
|
21
|
+
The above will start em-proxy on port 8080, relay and respond with data from port 8081, and also (optional) duplicate all traffic to ports 8082 and 8083 (and discard their responses).
|
22
|
+
|
23
|
+
|
24
|
+
## Simple port forwarding proxy
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
Proxy.start(:host => "0.0.0.0", :port => 80, :debug => true) do |conn|
|
28
|
+
conn.server :srv, :host => "127.0.0.1", :port => 81
|
29
|
+
|
30
|
+
# modify / process request stream
|
31
|
+
conn.on_data do |data|
|
32
|
+
p [:on_data, data]
|
33
|
+
data
|
34
|
+
end
|
35
|
+
|
36
|
+
# modify / process response stream
|
37
|
+
conn.on_response do |backend, resp|
|
38
|
+
p [:on_response, backend, resp]
|
39
|
+
resp
|
40
|
+
end
|
41
|
+
|
42
|
+
# termination logic
|
43
|
+
conn.on_finish do |backend, name|
|
44
|
+
p [:on_finish, name]
|
45
|
+
|
46
|
+
# terminate connection (in duplex mode, you can terminate when prod is done)
|
47
|
+
unbind if backend == :srv
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
For more examples see the /examples directory.
|
53
|
+
|
54
|
+
- SMTP Spam Filtering
|
55
|
+
- Duplicating traffic
|
56
|
+
- Selective forwarding
|
57
|
+
- Beanstalkd interceptor
|
58
|
+
- etc.
|
59
|
+
|
60
|
+
A schema-free MySQL proof of concept, via an EM-Proxy server:
|
61
|
+
|
62
|
+
- http://www.igvita.com/2010/03/01/schema-free-mysql-vs-nosql/
|
63
|
+
- Code in examples/schemaless-mysql
|
64
|
+
|
65
|
+
## License
|
66
|
+
|
67
|
+
The MIT License - Copyright (c) 2010 Ilya Grigorik
|
data/Rakefile
CHANGED
data/em-proxy.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "em-proxy"
|
6
|
-
s.version = "0.1.
|
6
|
+
s.version = "0.1.6"
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.authors = ["Ilya Grigorik"]
|
9
9
|
s.email = ["ilya@igvita.com"]
|
@@ -22,4 +22,4 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
23
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
24
|
s.require_paths = ["lib"]
|
25
|
-
end
|
25
|
+
end
|
data/examples/balancing.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'em-proxy'
|
2
|
+
require 'http/parser' # gem install http_parser.rb
|
3
|
+
require 'uuid' # gem install uuid
|
4
|
+
|
5
|
+
# > ruby em-proxy-http.rb
|
6
|
+
# > curl --proxy localhost:9889 www.google.com
|
7
|
+
|
8
|
+
host = "0.0.0.0"
|
9
|
+
port = 9889
|
10
|
+
puts "listening on #{host}:#{port}..."
|
11
|
+
|
12
|
+
Proxy.start(:host => host, :port => port) do |conn|
|
13
|
+
|
14
|
+
@p = Http::Parser.new
|
15
|
+
@p.on_headers_complete = proc do |h|
|
16
|
+
session = UUID.generate
|
17
|
+
puts "New session: #{session} (#{h.inspect})"
|
18
|
+
|
19
|
+
host, port = h['Host'].split(':')
|
20
|
+
conn.server session, :host => host, :port => (port || 80)
|
21
|
+
conn.relay_to_servers @buffer
|
22
|
+
|
23
|
+
@buffer.clear
|
24
|
+
end
|
25
|
+
|
26
|
+
@buffer = ''
|
27
|
+
|
28
|
+
conn.on_connect do |data,b|
|
29
|
+
puts [:on_connect, data, b].inspect
|
30
|
+
end
|
31
|
+
|
32
|
+
conn.on_data do |data|
|
33
|
+
@buffer << data
|
34
|
+
@p << data
|
35
|
+
|
36
|
+
data
|
37
|
+
end
|
38
|
+
|
39
|
+
conn.on_response do |backend, resp|
|
40
|
+
puts [:on_response, backend, resp].inspect
|
41
|
+
resp
|
42
|
+
end
|
43
|
+
|
44
|
+
conn.on_finish do |backend, name|
|
45
|
+
puts [:on_finish, name].inspect
|
46
|
+
end
|
47
|
+
end
|
data/lib/em-proxy/backend.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
module EventMachine
|
2
2
|
module ProxyServer
|
3
3
|
class Backend < EventMachine::Connection
|
4
|
-
attr_accessor :plexer, :
|
4
|
+
attr_accessor :plexer, :name, :debug
|
5
5
|
|
6
6
|
def initialize(debug = false)
|
7
7
|
@debug = debug
|
8
8
|
@connected = EM::DefaultDeferrable.new
|
9
|
-
@data = []
|
10
9
|
end
|
11
10
|
|
12
11
|
def connection_completed
|
@@ -17,7 +16,6 @@ module EventMachine
|
|
17
16
|
|
18
17
|
def receive_data(data)
|
19
18
|
debug [@name, data]
|
20
|
-
@data.push data
|
21
19
|
@plexer.relay_from_backend(@name, data)
|
22
20
|
end
|
23
21
|
|
data/lib/em-proxy/connection.rb
CHANGED
@@ -1,114 +1,114 @@
|
|
1
|
-
module EventMachine
|
2
|
-
module ProxyServer
|
3
|
-
class Connection < EventMachine::Connection
|
4
|
-
attr_accessor :debug
|
5
|
-
|
6
|
-
##### Proxy Methods
|
7
|
-
def on_data(&blk); @on_data = blk; end
|
8
|
-
def on_response(&blk); @on_response = blk; end
|
9
|
-
def on_finish(&blk); @on_finish = blk; end
|
10
|
-
def on_connect(&blk); @on_connect = blk; end
|
11
|
-
|
12
|
-
##### EventMachine
|
13
|
-
def initialize(options)
|
14
|
-
@debug = options[:debug] || false
|
15
|
-
@servers = {}
|
16
|
-
end
|
17
|
-
|
18
|
-
def receive_data(data)
|
19
|
-
debug [:connection, data]
|
20
|
-
processed = @on_data.call(data) if @on_data
|
21
|
-
|
22
|
-
return if processed == :async or processed.nil?
|
23
|
-
relay_to_servers(processed)
|
24
|
-
end
|
25
|
-
|
26
|
-
def relay_to_servers(processed)
|
27
|
-
if processed.is_a? Array
|
28
|
-
data, servers = *processed
|
29
|
-
|
30
|
-
# guard for "unbound" servers
|
31
|
-
servers = servers.collect {|s| @servers[s]}.compact
|
32
|
-
else
|
33
|
-
data = processed
|
34
|
-
servers ||= @servers.values.compact
|
35
|
-
end
|
36
|
-
|
37
|
-
servers.each do |s|
|
38
|
-
s.send_data data unless data.nil?
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
#
|
43
|
-
# initialize connections to backend servers
|
44
|
-
#
|
45
|
-
def server(name, opts)
|
46
|
-
srv = EventMachine::connect(opts[:host], opts[:port], EventMachine::ProxyServer::Backend, @debug) do |c|
|
47
|
-
c.name = name
|
48
|
-
c.plexer = self
|
49
|
-
c.proxy_incoming_to(self, 10240) if opts[:relay_server]
|
50
|
-
end
|
51
|
-
self.proxy_incoming_to(srv, 10240) if opts[:relay_client]
|
52
|
-
|
53
|
-
@servers[name] = srv
|
54
|
-
end
|
55
|
-
|
56
|
-
#
|
57
|
-
# [ip, port] of the connected client
|
58
|
-
#
|
59
|
-
def peer
|
60
|
-
peername = get_peername
|
61
|
-
@peer ||= peername ? Socket.unpack_sockaddr_in(peername).reverse : nil
|
62
|
-
end
|
63
|
-
|
64
|
-
#
|
65
|
-
# relay data from backend server to client
|
66
|
-
#
|
67
|
-
def relay_from_backend(name, data)
|
68
|
-
debug [:relay_from_backend, name, data]
|
69
|
-
|
70
|
-
data = @on_response.call(name, data) if @on_response
|
71
|
-
send_data data unless data.nil?
|
72
|
-
end
|
73
|
-
|
74
|
-
def connected(name)
|
75
|
-
debug [:connected]
|
76
|
-
@on_connect.call(name) if @on_connect
|
77
|
-
end
|
78
|
-
|
79
|
-
def unbind
|
80
|
-
debug [:unbind, :connection]
|
81
|
-
|
82
|
-
# terminate any unfinished connections
|
83
|
-
@servers.values.compact.each do |s|
|
84
|
-
s.close_connection
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def unbind_backend(name)
|
89
|
-
debug [:unbind_backend, name]
|
90
|
-
@servers[name] = nil
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def debug(*data)
|
106
|
-
if @debug
|
107
|
-
require 'pp'
|
108
|
-
pp data
|
109
|
-
puts
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
1
|
+
module EventMachine
|
2
|
+
module ProxyServer
|
3
|
+
class Connection < EventMachine::Connection
|
4
|
+
attr_accessor :debug
|
5
|
+
|
6
|
+
##### Proxy Methods
|
7
|
+
def on_data(&blk); @on_data = blk; end
|
8
|
+
def on_response(&blk); @on_response = blk; end
|
9
|
+
def on_finish(&blk); @on_finish = blk; end
|
10
|
+
def on_connect(&blk); @on_connect = blk; end
|
11
|
+
|
12
|
+
##### EventMachine
|
13
|
+
def initialize(options)
|
14
|
+
@debug = options[:debug] || false
|
15
|
+
@servers = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def receive_data(data)
|
19
|
+
debug [:connection, data]
|
20
|
+
processed = @on_data.call(data) if @on_data
|
21
|
+
|
22
|
+
return if processed == :async or processed.nil?
|
23
|
+
relay_to_servers(processed)
|
24
|
+
end
|
25
|
+
|
26
|
+
def relay_to_servers(processed)
|
27
|
+
if processed.is_a? Array
|
28
|
+
data, servers = *processed
|
29
|
+
|
30
|
+
# guard for "unbound" servers
|
31
|
+
servers = servers.collect {|s| @servers[s]}.compact
|
32
|
+
else
|
33
|
+
data = processed
|
34
|
+
servers ||= @servers.values.compact
|
35
|
+
end
|
36
|
+
|
37
|
+
servers.each do |s|
|
38
|
+
s.send_data data unless data.nil?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# initialize connections to backend servers
|
44
|
+
#
|
45
|
+
def server(name, opts)
|
46
|
+
srv = EventMachine::connect(opts[:host], opts[:port], EventMachine::ProxyServer::Backend, @debug) do |c|
|
47
|
+
c.name = name
|
48
|
+
c.plexer = self
|
49
|
+
c.proxy_incoming_to(self, 10240) if opts[:relay_server]
|
50
|
+
end
|
51
|
+
self.proxy_incoming_to(srv, 10240) if opts[:relay_client]
|
52
|
+
|
53
|
+
@servers[name] = srv
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# [ip, port] of the connected client
|
58
|
+
#
|
59
|
+
def peer
|
60
|
+
peername = get_peername
|
61
|
+
@peer ||= peername ? Socket.unpack_sockaddr_in(peername).reverse : nil
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# relay data from backend server to client
|
66
|
+
#
|
67
|
+
def relay_from_backend(name, data)
|
68
|
+
debug [:relay_from_backend, name, data]
|
69
|
+
|
70
|
+
data = @on_response.call(name, data) if @on_response
|
71
|
+
send_data data unless data.nil?
|
72
|
+
end
|
73
|
+
|
74
|
+
def connected(name)
|
75
|
+
debug [:connected]
|
76
|
+
@on_connect.call(name) if @on_connect
|
77
|
+
end
|
78
|
+
|
79
|
+
def unbind
|
80
|
+
debug [:unbind, :connection]
|
81
|
+
|
82
|
+
# terminate any unfinished connections
|
83
|
+
@servers.values.compact.each do |s|
|
84
|
+
s.close_connection
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def unbind_backend(name)
|
89
|
+
debug [:unbind_backend, name]
|
90
|
+
@servers[name] = nil
|
91
|
+
close = :close
|
92
|
+
|
93
|
+
if @on_finish
|
94
|
+
close = @on_finish.call(name)
|
95
|
+
end
|
96
|
+
|
97
|
+
# if all connections are terminated downstream, then notify client
|
98
|
+
if @servers.values.compact.size.zero? and close != :keep
|
99
|
+
close_connection_after_writing
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def debug(*data)
|
106
|
+
if @debug
|
107
|
+
require 'pp'
|
108
|
+
pp data
|
109
|
+
puts
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/spec/balancing_spec.rb
CHANGED
data/spec/helper.rb
CHANGED
data/spec/proxy_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'helper'
|
2
2
|
|
3
3
|
describe Proxy do
|
4
4
|
|
@@ -68,7 +68,7 @@ describe Proxy do
|
|
68
68
|
end
|
69
69
|
|
70
70
|
Proxy.start(:host => "0.0.0.0", :port => 8080) do |conn|
|
71
|
-
conn.server :
|
71
|
+
conn.server :bing, :host => "google.com", :port => 80
|
72
72
|
conn.server :yhoo, :host => "yahoo.com", :port => 80
|
73
73
|
conn.on_data { |data| data }
|
74
74
|
|
metadata
CHANGED
@@ -1,89 +1,73 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-proxy
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 1
|
8
|
-
- 5
|
9
|
-
version: 0.1.5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.6
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Ilya Grigorik
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-12-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: eventmachine
|
22
|
-
requirement: &
|
16
|
+
requirement: &2156629200 !ruby/object:Gem::Requirement
|
23
17
|
none: false
|
24
|
-
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
|
28
|
-
- 0
|
29
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
30
22
|
type: :runtime
|
31
23
|
prerelease: false
|
32
|
-
version_requirements: *
|
33
|
-
- !ruby/object:Gem::Dependency
|
24
|
+
version_requirements: *2156629200
|
25
|
+
- !ruby/object:Gem::Dependency
|
34
26
|
name: rspec
|
35
|
-
requirement: &
|
27
|
+
requirement: &2156628760 !ruby/object:Gem::Requirement
|
36
28
|
none: false
|
37
|
-
requirements:
|
38
|
-
- -
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
|
41
|
-
- 0
|
42
|
-
version: "0"
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
43
33
|
type: :development
|
44
34
|
prerelease: false
|
45
|
-
version_requirements: *
|
46
|
-
- !ruby/object:Gem::Dependency
|
35
|
+
version_requirements: *2156628760
|
36
|
+
- !ruby/object:Gem::Dependency
|
47
37
|
name: em-http-request
|
48
|
-
requirement: &
|
38
|
+
requirement: &2156628320 !ruby/object:Gem::Requirement
|
49
39
|
none: false
|
50
|
-
requirements:
|
51
|
-
- -
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
|
54
|
-
- 0
|
55
|
-
version: "0"
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
56
44
|
type: :development
|
57
45
|
prerelease: false
|
58
|
-
version_requirements: *
|
59
|
-
- !ruby/object:Gem::Dependency
|
46
|
+
version_requirements: *2156628320
|
47
|
+
- !ruby/object:Gem::Dependency
|
60
48
|
name: ansi
|
61
|
-
requirement: &
|
49
|
+
requirement: &2156627720 !ruby/object:Gem::Requirement
|
62
50
|
none: false
|
63
|
-
requirements:
|
64
|
-
- -
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
|
67
|
-
- 0
|
68
|
-
version: "0"
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
69
55
|
type: :development
|
70
56
|
prerelease: false
|
71
|
-
version_requirements: *
|
57
|
+
version_requirements: *2156627720
|
72
58
|
description: EventMachine Proxy DSL
|
73
|
-
email:
|
59
|
+
email:
|
74
60
|
- ilya@igvita.com
|
75
|
-
executables:
|
61
|
+
executables:
|
76
62
|
- em-proxy
|
77
63
|
extensions: []
|
78
|
-
|
79
64
|
extra_rdoc_files: []
|
80
|
-
|
81
|
-
files:
|
65
|
+
files:
|
82
66
|
- .gitignore
|
83
67
|
- .rspec
|
84
68
|
- Gemfile
|
85
69
|
- Gemfile.lock
|
86
|
-
- README.
|
70
|
+
- README.md
|
87
71
|
- Rakefile
|
88
72
|
- bin/em-proxy
|
89
73
|
- em-proxy.gemspec
|
@@ -92,6 +76,7 @@ files:
|
|
92
76
|
- examples/balancing.rb
|
93
77
|
- examples/beanstalkd_interceptor.rb
|
94
78
|
- examples/duplex.rb
|
79
|
+
- examples/http_proxy.rb
|
95
80
|
- examples/line_interceptor.rb
|
96
81
|
- examples/port_forward.rb
|
97
82
|
- examples/relay_port_forward.rb
|
@@ -107,41 +92,32 @@ files:
|
|
107
92
|
- spec/balancing_spec.rb
|
108
93
|
- spec/helper.rb
|
109
94
|
- spec/proxy_spec.rb
|
110
|
-
has_rdoc: true
|
111
95
|
homepage: http://github.com/igrigorik/em-proxy
|
112
96
|
licenses: []
|
113
|
-
|
114
97
|
post_install_message:
|
115
98
|
rdoc_options: []
|
116
|
-
|
117
|
-
require_paths:
|
99
|
+
require_paths:
|
118
100
|
- lib
|
119
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
102
|
none: false
|
121
|
-
requirements:
|
122
|
-
- -
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
|
125
|
-
|
126
|
-
- 0
|
127
|
-
version: "0"
|
128
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
108
|
none: false
|
130
|
-
requirements:
|
131
|
-
- -
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
|
134
|
-
segments:
|
135
|
-
- 0
|
136
|
-
version: "0"
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
137
113
|
requirements: []
|
138
|
-
|
139
114
|
rubyforge_project: em-proxy
|
140
|
-
rubygems_version: 1.
|
115
|
+
rubygems_version: 1.8.10
|
141
116
|
signing_key:
|
142
117
|
specification_version: 3
|
143
118
|
summary: EventMachine Proxy DSL
|
144
|
-
test_files:
|
119
|
+
test_files:
|
145
120
|
- spec/balancing_spec.rb
|
146
121
|
- spec/helper.rb
|
147
122
|
- spec/proxy_spec.rb
|
123
|
+
has_rdoc:
|
data/README.rdoc
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
= EM-Proxy
|
2
|
-
|
3
|
-
EventMachine Proxy DSL for writing high-performance transparent / intercepting proxies in Ruby.
|
4
|
-
|
5
|
-
- Slides from RailsConf 2009: http://bit.ly/D7oWB
|
6
|
-
- GoGaRuCo notes & Slides: http://www.igvita.com/2009/04/20/ruby-proxies-for-scale-and-monitoring/
|
7
|
-
|
8
|
-
== Getting started
|
9
|
-
|
10
|
-
$> gem install em-proxy
|
11
|
-
$> em-proxy
|
12
|
-
Usage: em-proxy [options]
|
13
|
-
-l, --listen [PORT] Port to listen on
|
14
|
-
-d, --duplex [host:port, ...] List of backends to duplex data to
|
15
|
-
-r, --relay [hostname:port] Relay endpoint: hostname:port
|
16
|
-
-v, --verbose Run in debug mode
|
17
|
-
|
18
|
-
$> em-proxy -l 8080 -r localhost:8081 -d localhost:8082,localhost:8083 -v
|
19
|
-
|
20
|
-
The above will start em-proxy on port 8080, relay and respond with data from port 8081, and also (optional) duplicate all traffic to ports 8082 and 8083 (and discard their responses).
|
21
|
-
|
22
|
-
== Simple port forwarding proxy
|
23
|
-
|
24
|
-
Proxy.start(:host => "0.0.0.0", :port => 80, :debug => true) do |conn|
|
25
|
-
conn.server :srv, :host => "127.0.0.1", :port => 81
|
26
|
-
|
27
|
-
# modify / process request stream
|
28
|
-
conn.on_data do |data|
|
29
|
-
p [:on_data, data]
|
30
|
-
data
|
31
|
-
end
|
32
|
-
|
33
|
-
# modify / process response stream
|
34
|
-
conn.on_response do |backend, resp|
|
35
|
-
p [:on_response, backend, resp]
|
36
|
-
resp
|
37
|
-
end
|
38
|
-
|
39
|
-
# termination logic
|
40
|
-
conn.on_finish do |backend, name|
|
41
|
-
p [:on_finish, name]
|
42
|
-
|
43
|
-
# terminate connection (in duplex mode, you can terminate when prod is done)
|
44
|
-
unbind if backend == :srv
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
For more examples see the /examples directory.
|
49
|
-
- SMTP Spam Filtering
|
50
|
-
- Duplicating traffic
|
51
|
-
- Selective forwarding
|
52
|
-
- Beanstalkd interceptor
|
53
|
-
- etc.
|
54
|
-
|
55
|
-
A schema-free MySQL proof of concept, via an EM-Proxy server:
|
56
|
-
- http://www.igvita.com/2010/03/01/schema-free-mysql-vs-nosql/
|
57
|
-
- Code in examples/schemaless-mysql
|
58
|
-
|
59
|
-
== License
|
60
|
-
|
61
|
-
(The MIT License)
|
62
|
-
|
63
|
-
Copyright (c) 2010 Ilya Grigorik
|
64
|
-
|
65
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
66
|
-
a copy of this software and associated documentation files (the
|
67
|
-
'Software'), to deal in the Software without restriction, including
|
68
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
69
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
70
|
-
permit persons to whom the Software is furnished to do so, subject to
|
71
|
-
the following conditions:
|
72
|
-
|
73
|
-
The above copyright notice and this permission notice shall be
|
74
|
-
included in all copies or substantial portions of the Software.
|
75
|
-
|
76
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
77
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
78
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
79
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
80
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
81
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
82
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|