experella-proxy 0.0.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/.gitignore +15 -0
- data/Gemfile +3 -0
- data/README.md +219 -0
- data/Rakefile +25 -0
- data/TODO.txt +20 -0
- data/bin/experella-proxy +54 -0
- data/config/default/404.html +16 -0
- data/config/default/503.html +18 -0
- data/config/default/config.rb +64 -0
- data/config/default/ssl/certs/experella-proxy.pem +18 -0
- data/config/default/ssl/private/experella-proxy.key +28 -0
- data/dev/experella-proxy +62 -0
- data/experella-proxy.gemspec +39 -0
- data/lib/experella-proxy/backend.rb +58 -0
- data/lib/experella-proxy/backend_server.rb +100 -0
- data/lib/experella-proxy/configuration.rb +154 -0
- data/lib/experella-proxy/connection.rb +557 -0
- data/lib/experella-proxy/connection_manager.rb +167 -0
- data/lib/experella-proxy/globals.rb +37 -0
- data/lib/experella-proxy/http_status_codes.rb +45 -0
- data/lib/experella-proxy/proxy.rb +61 -0
- data/lib/experella-proxy/request.rb +106 -0
- data/lib/experella-proxy/response.rb +204 -0
- data/lib/experella-proxy/server.rb +68 -0
- data/lib/experella-proxy/version.rb +15 -0
- data/lib/experella-proxy.rb +93 -0
- data/spec/echo-server/echo_server.rb +49 -0
- data/spec/experella-proxy/backend_server_spec.rb +101 -0
- data/spec/experella-proxy/configuration_spec.rb +27 -0
- data/spec/experella-proxy/connection_manager_spec.rb +159 -0
- data/spec/experella-proxy/experella-proxy_spec.rb +471 -0
- data/spec/experella-proxy/request_spec.rb +88 -0
- data/spec/experella-proxy/response_spec.rb +44 -0
- data/spec/fixtures/404.html +16 -0
- data/spec/fixtures/503.html +18 -0
- data/spec/fixtures/spec.log +331 -0
- data/spec/fixtures/test_config.rb +34 -0
- data/spec/spec.log +235 -0
- data/spec/spec_helper.rb +35 -0
- data/test/sinatra/hello_world_server.rb +17 -0
- data/test/sinatra/server_one.rb +89 -0
- data/test/sinatra/server_two.rb +89 -0
- metadata +296 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
#Experella-Proxy
|
2
|
+
|
3
|
+
A balancing EventMachine reverse proxy based on [em-proxy](https://github.com/igrigorik/em-proxy)
|
4
|
+
|
5
|
+
Configurable in pure ruby!
|
6
|
+
|
7
|
+
Supports:
|
8
|
+
|
9
|
+
+ Persistent connections and HTTP Pipelining for clients
|
10
|
+
+ Response streaming
|
11
|
+
+ Post Request data streaming
|
12
|
+
+ Request header routing logic completely configurable for each server
|
13
|
+
+ Request header manipulation completely configurable for each server
|
14
|
+
+ Daemonized control using ruby [Daemons](http://daemons.rubyforge.org/)
|
15
|
+
+ TLS support and a default self-signed ssl certification
|
16
|
+
|
17
|
+
Proxy uses [http_parser](https://github.com/tmm1/http_parser.rb) to parse http data and is thereby subject to the parsers restrictions
|
18
|
+
|
19
|
+
The proxy is build for low proxy to server latency and does not support persistent connections to servers. Keep that in mind
|
20
|
+
as i can severely influence proxy performance overhead.
|
21
|
+
|
22
|
+
It balances for every single http-request and not per client/connection.
|
23
|
+
|
24
|
+
##Install as Gem
|
25
|
+
|
26
|
+
To use experella-proxy simply install it as a gem.
|
27
|
+
|
28
|
+
```
|
29
|
+
gem install experella-proxy
|
30
|
+
```
|
31
|
+
|
32
|
+
##How to start
|
33
|
+
|
34
|
+
Experella-Proxy is controlled by ruby Daemons default commands (run, start, restart, stop) and provides
|
35
|
+
a template config initialization command (init destination).
|
36
|
+
|
37
|
+
run, start and restart require an absolute config file path.
|
38
|
+
|
39
|
+
To initialize the proxy with default config files init the proxy to a directory of your choice.
|
40
|
+
|
41
|
+
For example
|
42
|
+
|
43
|
+
```
|
44
|
+
$> experella-proxy init ~
|
45
|
+
```
|
46
|
+
|
47
|
+
will initialize default config to $HOME/proxy
|
48
|
+
|
49
|
+
|
50
|
+
Then simply use:
|
51
|
+
|
52
|
+
```
|
53
|
+
$> experella-proxy start -- --config=~/proxy/config.rb
|
54
|
+
$> experella-proxy restart -- --config=~/proxy/config.rb
|
55
|
+
$> experella-proxy stop
|
56
|
+
```
|
57
|
+
to control the proxy with the default config file.
|
58
|
+
|
59
|
+
|
60
|
+
### BASE_PORT option for default config
|
61
|
+
|
62
|
+
To set other base port you have to prefix the previous commands with BASE_PORT=xxxx e.g.
|
63
|
+
|
64
|
+
Running ports below 1024 probably requires "rvmsudo" to run properly
|
65
|
+
|
66
|
+
```
|
67
|
+
$> BASE_PORT=3000 experella-proxy start -- --config=~/proxy/config.rb
|
68
|
+
```
|
69
|
+
|
70
|
+
##Config file
|
71
|
+
|
72
|
+
You need to provide a valid config file for the proxy to run.
|
73
|
+
|
74
|
+
Config files use a ruby DSL with the following options
|
75
|
+
|
76
|
+
###Backend Server
|
77
|
+
|
78
|
+
Each server is configured independent of other servers, so each desired routing dependency has to be added manually.
|
79
|
+
i.e. if you want to route an inimitable request to an unique backend, you have to exclude that match in all other servers.
|
80
|
+
|
81
|
+
|
82
|
+
```
|
83
|
+
backend Takes an options hash defining a backend_server
|
84
|
+
required keys => :host Host address of the Server, can be IP or domain, String
|
85
|
+
:port Port of the Server, Integervalue as String
|
86
|
+
|
87
|
+
optional keys => :name Name of the Server used in the Logger and Cashing, String
|
88
|
+
Will default to #{host}:#{port} but needs to be unique, though theoretical there can be
|
89
|
+
multiple servers with the same host:port value pair!
|
90
|
+
|
91
|
+
:concurrency max Number of concurrent connections, Integervalue as String, Default is 1
|
92
|
+
|
93
|
+
:accepts Hash containing keys matching HTTP headers or URI :path, :port, :query
|
94
|
+
Values are Regexp as Strings or as Regex, use ^((?!pattern).)*$ to negate matching
|
95
|
+
Care: Will match any Header/value pairs not defined in the accepts Hash
|
96
|
+
|
97
|
+
:mangle Hash containing keys matching HTTP headers. Values can be callable block or Strings
|
98
|
+
Mangle modifies the header value based on the given block
|
99
|
+
or replaces the header value with the String
|
100
|
+
```
|
101
|
+
|
102
|
+
####Example
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
backend(:name => "Srv1", :host => "192.168.0.10", :port => "80", :concurrency => "1",
|
106
|
+
:accepts => {"request_url" => "^((?!/(#{not-for-srv1})($|/)).)*$"},
|
107
|
+
:mangle => {"Host" => lambda{ |host|
|
108
|
+
if host.match(/localhost/)
|
109
|
+
'www.host-i-need.com'
|
110
|
+
else
|
111
|
+
host
|
112
|
+
end
|
113
|
+
}
|
114
|
+
}
|
115
|
+
)
|
116
|
+
```
|
117
|
+
###Logging
|
118
|
+
|
119
|
+
```
|
120
|
+
set_logger specifies the Logger used by the program. The Logger must support debug/info/warn/error/fatal functions
|
121
|
+
```
|
122
|
+
|
123
|
+
###Proxy Server
|
124
|
+
|
125
|
+
```
|
126
|
+
set_proxy Add proxy as Hash with :host => "string-ip/domain", :port => Fixnum, :options => Hash
|
127
|
+
The proxy will listen on every host:port hash added with this function.
|
128
|
+
:options can activate :tls with given file paths to :private_key_file and :cert_chain_file
|
129
|
+
file paths are relative to the config file directory
|
130
|
+
```
|
131
|
+
####Example
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
set_proxy(:host => "127.0.0.1", :port => 8080)
|
135
|
+
set_proxy(:host => "127.0.0.1", :port => 443,
|
136
|
+
:options => {:tls => true,
|
137
|
+
:private_key_file => 'ssl/private/experella_proxy.key',
|
138
|
+
:cert_chain_file => 'ssl/certs/experella_proxy.pem'})
|
139
|
+
set_proxy(:host => "127.0.0.2", :port => 8080)
|
140
|
+
set_proxy(:host => "192.168.100.168", :port => 6666)
|
141
|
+
```
|
142
|
+
|
143
|
+
###Connection timeout
|
144
|
+
|
145
|
+
```
|
146
|
+
set_timeout Time as float when an idle persistent connection gets closed (no receive/send events occured)
|
147
|
+
```
|
148
|
+
|
149
|
+
###Error pages
|
150
|
+
|
151
|
+
```
|
152
|
+
set_error_pages Add html error-pages to the proxy, requires 2 arguments
|
153
|
+
1st arg: the error code as Fixnum
|
154
|
+
2nd arg: path to an error page html file relative to the config file directory
|
155
|
+
Currently 404 and 503 error codes are supported
|
156
|
+
```
|
157
|
+
|
158
|
+
####Example
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
set_error_pages(404, "404.html")
|
162
|
+
set_error_pages(503, "503.html")
|
163
|
+
```
|
164
|
+
|
165
|
+
|
166
|
+
## Modify connection logic and data streams
|
167
|
+
|
168
|
+
Override server's run function
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
def run
|
172
|
+
|
173
|
+
Proxy.start(options = {}) do |conn|
|
174
|
+
|
175
|
+
log.info msec + "new Connection @" + signature.to_s
|
176
|
+
|
177
|
+
# called on successful backend connection
|
178
|
+
conn.on_connect do |backend|
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
# modify / process request stream
|
183
|
+
# and return modified data
|
184
|
+
conn.on_data do |data|
|
185
|
+
data
|
186
|
+
end
|
187
|
+
|
188
|
+
# modify / process response stream+
|
189
|
+
# and return modified response
|
190
|
+
conn.on_response do |backend, resp|
|
191
|
+
resp
|
192
|
+
end
|
193
|
+
|
194
|
+
# termination logic
|
195
|
+
conn.on_finish do |backend|
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
# called if client finishes connection
|
200
|
+
conn.on_unbind do
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
```
|
207
|
+
|
208
|
+
## Additional Information
|
209
|
+
|
210
|
+
+ [em-proxy](https://github.com/igrigorik/em-proxy)
|
211
|
+
+ [http_parser](https://github.com/tmm1/http_parser.rb)
|
212
|
+
+ [Eventmachine](https://github.com/eventmachine/eventmachine)
|
213
|
+
+ [Daemons](http://daemons.rubyforge.org/)
|
214
|
+
+ [What proxies must do](http://www.mnot.net/blog/2011/07/11/what_proxies_must_do)
|
215
|
+
|
216
|
+
|
217
|
+
## License
|
218
|
+
|
219
|
+
MIT License - Copyright (c) 2014 Dennis-Florian Herr @Experteer GmbH
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'yard'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
YARD::Rake::YardocTask.new(:yardoc)
|
8
|
+
|
9
|
+
desc "Start Sinatra Server one on port 4567"
|
10
|
+
task :sinatra_one do
|
11
|
+
require 'test/sinatra/server_one'
|
12
|
+
ServerOne.run!(:port => 4567)
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Start Sinatra Server two port 4568"
|
16
|
+
task :sinatra_two do
|
17
|
+
require 'test/sinatra/server_two'
|
18
|
+
ServerTwo.run!(:port => 4568)
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Start Hello World! Sinatra Server port 4569"
|
22
|
+
task :sinatra_hello_world do
|
23
|
+
require 'test/sinatra/hello_world_server'
|
24
|
+
HelloWorldServer.run!(:port => 4569)
|
25
|
+
end
|
data/TODO.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
TODO:
|
2
|
+
|
3
|
+
General:
|
4
|
+
|
5
|
+
- Benchmarks for readme
|
6
|
+
- Configuration routing debugging tool
|
7
|
+
|
8
|
+
Performance:
|
9
|
+
|
10
|
+
- improve server matching
|
11
|
+
* avoid negative regexp, e.g. add reject option instead of negative accept
|
12
|
+
* group servers which match same requests
|
13
|
+
* probably add a option for "fallback" servers
|
14
|
+
|
15
|
+
Features:
|
16
|
+
|
17
|
+
- self configuring backends
|
18
|
+
* detect disconnected backends
|
19
|
+
- improve middleware support
|
20
|
+
- SPDY
|
data/bin/experella-proxy
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path(File.join(File.dirname(__FILE__), '../lib/'))
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
ARGV << '--help' if ARGV.empty?
|
8
|
+
|
9
|
+
if ARGV[0] == "init"
|
10
|
+
if ARGV[1] && File.directory?(File.expand_path(ARGV[1]))
|
11
|
+
source_dir = File.expand_path(File.join(File.dirname(__FILE__), "/../config/default/"))
|
12
|
+
dest_dir = File.join(File.expand_path(ARGV[1]), "proxy")
|
13
|
+
FileUtils.copy_entry source_dir, dest_dir
|
14
|
+
puts "Initialized template config to #{dest_dir}"
|
15
|
+
else
|
16
|
+
puts "ERROR: #{File.expand_path(ARGV[1])} is not a directory"
|
17
|
+
puts "Please provide an existing directory to initialize to as second argument"
|
18
|
+
end
|
19
|
+
elsif ["start", "stop", "restart", "reload", "run", "zap", "status"].include? ARGV[0]
|
20
|
+
require 'daemons'
|
21
|
+
Daemons.run(File.join(lib, 'experella-proxy.rb'))
|
22
|
+
else
|
23
|
+
unless ARGV[0] == "--help" || ARGV[0] == "-h"
|
24
|
+
puts "ERROR no command given"
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
puts "To control the proxy use: experella-proxy <command> <options> -- <application options>"
|
28
|
+
puts
|
29
|
+
puts "* where <command> is one of Daemons:"
|
30
|
+
puts " start start an instance of the application"
|
31
|
+
puts " stop stop all instances of the application"
|
32
|
+
puts " restart stop all instances and restart them afterwards"
|
33
|
+
puts " reload send a SIGHUP to all instances of the application"
|
34
|
+
puts " run start the application and stay on top"
|
35
|
+
puts " zap set the application to a stopped state"
|
36
|
+
puts " status show status (PID) of application instances"
|
37
|
+
puts
|
38
|
+
puts "* and where <options> may contain several of the following:"
|
39
|
+
puts " -t, --ontop Stay on top (does not daemonize)"
|
40
|
+
puts " -f, --force Force operation"
|
41
|
+
puts " -n, --no_wait Do not wait for processes to stop"
|
42
|
+
puts
|
43
|
+
puts "* and where <applicaion options> are"
|
44
|
+
puts " --config=CONFIGFILE absolute path to the proxy config file"
|
45
|
+
puts
|
46
|
+
puts
|
47
|
+
puts "To initialize the proxy use: experella-proxy init <path>"
|
48
|
+
puts
|
49
|
+
puts "* where <path> is the location the config files get copied to"
|
50
|
+
puts
|
51
|
+
puts "Common options: "
|
52
|
+
puts " -h, --help Show this message"
|
53
|
+
puts " --version Show daemons version"
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<style type="text/css"> body {
|
5
|
+
text-align: center;
|
6
|
+
font-family: helvetica, arial;
|
7
|
+
font-size: 22px;
|
8
|
+
color: #000;
|
9
|
+
margin: 20px
|
10
|
+
}
|
11
|
+
</style>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<h2>404 Page not found!</h2>
|
15
|
+
</body>
|
16
|
+
</html>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<style type="text/css"> body {
|
5
|
+
text-align: center;
|
6
|
+
font-family: helvetica, arial;
|
7
|
+
font-size: 22px;
|
8
|
+
color: #000;
|
9
|
+
margin: 20px
|
10
|
+
|
11
|
+
}
|
12
|
+
|
13
|
+
</style>
|
14
|
+
</head>
|
15
|
+
<body>
|
16
|
+
<h2> 503 Service unavailable!</h2>
|
17
|
+
</body>
|
18
|
+
</html>
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#Backend Server
|
2
|
+
base_backend_port=(ENV["BASE_PORT"] : 4000).to_i
|
3
|
+
backend1_port=base_backend_port+1
|
4
|
+
backend2_port=base_backend_port+2
|
5
|
+
|
6
|
+
# add servers in schema, :name, :host, :port, :concurrency,
|
7
|
+
# :host and :port are required, everything else is optional though name needs to be unique!
|
8
|
+
# :accepts {"header" => regex} hash, :mangle {"header" => "string"||lambda do |header-value|}
|
9
|
+
# accepts hash can additionally use uri :port, :path, :query for more efficient comparison
|
10
|
+
# mangle hash can modify any http headers, use strings for simple replace, use lambda for logic
|
11
|
+
# accepts and mangle are optional, but care: not using accepts means the server accepts every request and backends will
|
12
|
+
# always ignore the settings of any other backend server.
|
13
|
+
# use ^((?!pattern).)*$ to negate matching
|
14
|
+
|
15
|
+
#template backend servers
|
16
|
+
|
17
|
+
backend(:name => "srv1", :host => "localhost", :port => backend1_port, :concurrency => "1000",
|
18
|
+
:accepts => {"request_url" => "^((?!/(srv2)($|/)).)*$"}
|
19
|
+
)
|
20
|
+
|
21
|
+
backend(:name => "srv2", :host_port => "localhost:#{backend2_port}", :concurrency => "1",
|
22
|
+
:accepts => {"request_url" => "/(srv2)($|/)"},
|
23
|
+
:mangle => {"Host" => lambda { |host|
|
24
|
+
if host.match(/127.0.0/)
|
25
|
+
'localhost'
|
26
|
+
else
|
27
|
+
host
|
28
|
+
end
|
29
|
+
}
|
30
|
+
}
|
31
|
+
)
|
32
|
+
|
33
|
+
# experimental!
|
34
|
+
# web support if used as a forward proxy. care, not all webservers accept http-proxy standard (e.g. wikimedia)
|
35
|
+
# Host and Port will be set according to Requests Host header instead of :host and :port keys.
|
36
|
+
# backend(:name => "web", :host => "0.0.0.0", :port => "80", :concurrency => "1000",
|
37
|
+
# :accepts => {"Host" => "^((?!localhost).)*$"}
|
38
|
+
# )
|
39
|
+
|
40
|
+
require 'logger'
|
41
|
+
|
42
|
+
# set a logger. Has to support debug/info/warn/error/fatal logger functions
|
43
|
+
set_logger Logger.new($stdout)
|
44
|
+
logger.level = Logger::WARN
|
45
|
+
|
46
|
+
# set proxy servers here, listens on every host, port hash pair
|
47
|
+
# you can add one pair per call to set_proxy(hsh)
|
48
|
+
# additionally you can activate ssl with provided private_key and cert_chain files
|
49
|
+
set_proxy(:host => "localhost", :port => base_backend_port)
|
50
|
+
set_proxy(:host => "localhost", :port => 443,
|
51
|
+
:options => {:tls => true,
|
52
|
+
:private_key_file => 'ssl/private/experella-proxy.key',
|
53
|
+
:cert_chain_file => 'ssl/certs/experella-proxy.pem'}
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
# set the timeout in seconds. Will unbind a keep-alive connection
|
58
|
+
# if no send/receive event occured in specified seconds
|
59
|
+
set_timeout(30.0)
|
60
|
+
|
61
|
+
# provide errorpage locations. first arguument is error code, second is (html) file location in configfile folder
|
62
|
+
set_error_pages(404, "404.html")
|
63
|
+
set_error_pages(503, "503.html")
|
64
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIC4TCCAcmgAwIBAgIJAN8pDjDjYU8xMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
|
3
|
+
BAMTCWxvY2FsaG9zdDAeFw0xNDAxMjIxNTI2NTZaFw0yNDAxMjAxNTI2NTZaMBQx
|
4
|
+
EjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
5
|
+
ggEBAMOf6ah6DhHpIjEkJDrNVddo82Z+Bzk3OCyqaGhyWSDN7kQermErxqw0ioeK
|
6
|
+
1p6j+od1aVcwjWds6TdRjPPlIb1ZmlAhwrCedF7TAN76jRVoay4reRzA5SJ4lR9i
|
7
|
+
BkpYJbE7bx1l16dvnpwfP44thiPp4jHGwtkgZCnUsqyIW03Ssn6P5hGQqSBgy6GO
|
8
|
+
Hb0ZuyyVIENCHaRMuFjjU4jrZzwcIt/nVWx2M1njxFDHt2FLpvtKtGkp8abrrQO6
|
9
|
+
TeEpTUDQcncrMzXhm80Kr6PY9FVNauuOpWZXhbK0lndxyXQC3eN+8eeCFDV0EfU8
|
10
|
+
pRkc+dfGFBI8zuHZY0VSeUsc8uMCAwEAAaM2MDQwCQYDVR0TBAIwADAnBgNVHREE
|
11
|
+
IDAehwR/AAABhwR/AAAChwR/AAADhwR/AAAEhwR/AAAFMA0GCSqGSIb3DQEBBQUA
|
12
|
+
A4IBAQBv4/A9F7lQ/TGVO28RoWGZrCouMhkmVC/mo1SQxpkGY0VlydU04mWAiayv
|
13
|
+
32Fyy0SPq/2YgpFzAyXLVZ2hO/4NEHjjpd1utHWEXxVGy8nqMS73y7XOuc7bkT7V
|
14
|
+
uqvxA0WgwtD9EOG+XIiRszybcR/C1Dpg37Ct9ZA1wmFQr5C19Hl0ki6PKkaGuy/I
|
15
|
+
NGMtdgxGSKzCGTwQD7rclUbvf5QZYN+uoyZoC3yJ47sAER8CMpAYTl/GU34vL7p2
|
16
|
+
NJiPH3Y570l6II96JU7nsdC6UA4sUx/H9HhDsd0TSXtLONqQU03M9qDckgmf+x0C
|
17
|
+
oIjTcEDbcsGuPuo6j1HYrAzNEkso
|
18
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,28 @@
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
2
|
+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDDn+moeg4R6SIx
|
3
|
+
JCQ6zVXXaPNmfgc5Nzgsqmhoclkgze5EHq5hK8asNIqHitaeo/qHdWlXMI1nbOk3
|
4
|
+
UYzz5SG9WZpQIcKwnnRe0wDe+o0VaGsuK3kcwOUieJUfYgZKWCWxO28dZdenb56c
|
5
|
+
Hz+OLYYj6eIxxsLZIGQp1LKsiFtN0rJ+j+YRkKkgYMuhjh29GbsslSBDQh2kTLhY
|
6
|
+
41OI62c8HCLf51VsdjNZ48RQx7dhS6b7SrRpKfGm660Duk3hKU1A0HJ3KzM14ZvN
|
7
|
+
Cq+j2PRVTWrrjqVmV4WytJZ3ccl0At3jfvHnghQ1dBH1PKUZHPnXxhQSPM7h2WNF
|
8
|
+
UnlLHPLjAgMBAAECggEACqmInrooUimWx37kyp+uchMyUP/FfQTZdvXCww6YdQVE
|
9
|
+
W0ogzwMHzRMACeszT2o4mXF40FvBGUYCYBV9zT1L3Xoowv1UEzRPu2tcvMqDLguG
|
10
|
+
6/lKnJqW4o4X8qHxHdQ4GbTXlY6bdnDLAE9js2gfy41P2s6uiA8P5ofFRUoZT+B3
|
11
|
+
jczy86d5FFD0RYnFOIAxR2s1MNKzbh+400L+PdLu3p8+PsdCgFD703eyCtnLIxFm
|
12
|
+
NkGNpNnBwKSD3kufwOqtht+iIOrpR2LwBAZszO7h4P9/1gwX++296sq4uK7px3hh
|
13
|
+
2n/vnv/k/IB0Ewp20vyVibTzrJees+A2x28GduW6wQKBgQDv/pJ/EakoMDWs5fFq
|
14
|
+
4DFaiy+YznE5iUce74yxZusxTaCBMacbPYWLqs3ZtZ2weo161XLcyNEKkOALoslt
|
15
|
+
4tcLuLlzbBBR3o0Z6ggmXgvgrvtd4hN7IfjcxzRp7jAhlZx2j7JfXiNsmJ+yQ+UZ
|
16
|
+
FJejcaf4zNUtD1tP/Pc91bwCWwKBgQDQq9Cgk/DpTXp8lVaNbrk8QC3e48RCXLsj
|
17
|
+
qUeeWPVEcMSr2yafH38fMdfi+FhTYbAIn/uvCHPzPbsJ0DT04cQtWmztOuex4A7j
|
18
|
+
biiazkfbwb4ROe8fXzGFDCLAyhItkyLwuXCvR8GO7iRQiQaSOHOGrsEgCK40WU6V
|
19
|
+
dTwiqq+oGQKBgQDZd0tV2zH1maG5lu7oUlhGXGL3yvEsGqmYbaaGReUOWvH6v3xV
|
20
|
+
oay2P0KiaQCHnrU+vdWEHG/XbCmoQYzWhrsoAu4AmcY7+TbQaZGS+ps2sDhT/Px8
|
21
|
+
Ee+IVvW2mz9/3yrVACa4ZfwhdjcW+JDK5i71ypJTT4BHgWfTljyPCnJ/iwKBgQCC
|
22
|
+
7huEde8mY//j5cweCAhgHqDphp5hSU/+qzuNxqF2ZQ9yCZrtItUfnKWp+0toXhYX
|
23
|
+
A1LnW3VtfSE7ohFoSbRPBLruCxTPzhdpang90grSf3kj0+cPFyq6IYg40VGgmP7G
|
24
|
+
boSe5nYzmYbdpWyjGJqcOlBhKjEsFZEyRBIMam63GQKBgC76YY/TEoPV7BPcvaDc
|
25
|
+
4p7d4YC+KLidy6tyOx2hn8a0FAUmgrQP0Jbl9pMf+oVTGJm460ASW+z6ZQjilx0s
|
26
|
+
4PCGWXNioJJOdTWRRHB2RjrHOU3MXKbBJB4JBg4n+fBtEEE9nP0orCpsDVnGSlep
|
27
|
+
t7n4VlIzT0CrlpXYiJQaG6hq
|
28
|
+
-----END PRIVATE KEY-----
|
data/dev/experella-proxy
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# binary file for developers
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
Bundler.setup
|
7
|
+
|
8
|
+
#NOTE: This is exactly the same as /bin/experella-proxy from here
|
9
|
+
|
10
|
+
lib = File.expand_path(File.join(File.dirname(__FILE__), '../lib/'))
|
11
|
+
|
12
|
+
require 'fileutils'
|
13
|
+
|
14
|
+
ARGV << '--help' if ARGV.empty?
|
15
|
+
|
16
|
+
if ARGV[0] == "init"
|
17
|
+
if ARGV[1] && File.directory?(File.expand_path(ARGV[1]))
|
18
|
+
source_dir = File.expand_path(File.join(File.dirname(__FILE__), "/../config/default/"))
|
19
|
+
dest_dir = File.join(File.expand_path(ARGV[1]), "proxy")
|
20
|
+
FileUtils.copy_entry source_dir, dest_dir
|
21
|
+
puts "Initialized template config to #{dest_dir}"
|
22
|
+
else
|
23
|
+
puts "ERROR: #{File.expand_path(ARGV[1])} is not a directory"
|
24
|
+
puts "Please provide an existing directory to initialize to as second argument"
|
25
|
+
end
|
26
|
+
elsif ["start", "stop", "restart", "reload", "run", "zap", "status"].include? ARGV[0]
|
27
|
+
require 'daemons'
|
28
|
+
Daemons.run(File.join(lib, 'experella-proxy.rb'))
|
29
|
+
else
|
30
|
+
unless ARGV[0] == "--help" || ARGV[0] == "-h"
|
31
|
+
puts "ERROR no command given"
|
32
|
+
puts
|
33
|
+
end
|
34
|
+
puts "To control the proxy use: experella-proxy <command> <options> -- <application options>"
|
35
|
+
puts
|
36
|
+
puts "* where <command> is one of Daemons:"
|
37
|
+
puts " start start an instance of the application"
|
38
|
+
puts " stop stop all instances of the application"
|
39
|
+
puts " restart stop all instances and restart them afterwards"
|
40
|
+
puts " reload send a SIGHUP to all instances of the application"
|
41
|
+
puts " run start the application and stay on top"
|
42
|
+
puts " zap set the application to a stopped state"
|
43
|
+
puts " status show status (PID) of application instances"
|
44
|
+
puts
|
45
|
+
puts "* and where <options> may contain several of the following:"
|
46
|
+
puts " -t, --ontop Stay on top (does not daemonize)"
|
47
|
+
puts " -f, --force Force operation"
|
48
|
+
puts " -n, --no_wait Do not wait for processes to stop"
|
49
|
+
puts
|
50
|
+
puts "* and where <applicaion options> are"
|
51
|
+
puts " --config=CONFIGFILE absolute path to the proxy config file"
|
52
|
+
puts
|
53
|
+
puts
|
54
|
+
puts "To initialize the proxy use: experella-proxy init <path>"
|
55
|
+
puts
|
56
|
+
puts "* where <path> is the location the config files get copied to"
|
57
|
+
puts
|
58
|
+
puts "Common options: "
|
59
|
+
puts " -h, --help Show this message"
|
60
|
+
puts " --version Show daemons version"
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'experella-proxy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "experella-proxy"
|
8
|
+
spec.version = ExperellaProxy::VERSION
|
9
|
+
spec.authors = ["Dennis-Florian Herr"]
|
10
|
+
spec.email = ["dennis.herr@experteer.com"]
|
11
|
+
spec.description = 'a balancing & routing proxy, see README for more details'
|
12
|
+
spec.summary = 'experella-proxy gem'
|
13
|
+
spec.homepage = "https://github.com/experteer/experella-proxy"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.add_runtime_dependency "daemons", "~> 1.1.4"
|
17
|
+
spec.add_runtime_dependency "eventmachine", "~> 1.0.3"
|
18
|
+
spec.add_runtime_dependency "http_parser.rb", "~> 0.5.3"
|
19
|
+
|
20
|
+
spec.add_development_dependency "rake", "~> 10.1.0"
|
21
|
+
# specs
|
22
|
+
spec.add_development_dependency "rspec", "2.14.1"
|
23
|
+
spec.add_development_dependency "posix-spawn"
|
24
|
+
spec.add_development_dependency "em-http-request"
|
25
|
+
# dev testing
|
26
|
+
spec.add_development_dependency "sinatra", "1.4.3"
|
27
|
+
spec.add_development_dependency "thin", "~> 1.5.1"
|
28
|
+
# documentation tool
|
29
|
+
spec.add_development_dependency "yard", "~> 0.8.7.3"
|
30
|
+
spec.add_development_dependency "redcarpet", "~> 2.3.0"
|
31
|
+
|
32
|
+
spec.files = Dir["bin/*"] + Dir["dev/*"] + Dir["lib/**/*"] + Dir["config/default/**/*"]
|
33
|
+
spec.files += Dir["spec/**/*"] + Dir["test/sinatra/*"]
|
34
|
+
spec.files += [".gitignore", "Gemfile", "experella-proxy.gemspec", "README.md", "TODO.txt", "Rakefile"]
|
35
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
36
|
+
spec.test_files = spec.files.grep(%r{^(test|spec)/})
|
37
|
+
spec.extra_rdoc_files = ['README.md']
|
38
|
+
spec.require_paths = ["lib"]
|
39
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ExperellaProxy
|
2
|
+
# The Proxies connection to the backend server
|
3
|
+
#
|
4
|
+
# This class will never be directly initiated by user code, but initializing gets triggered in client {Connection}
|
5
|
+
class Backend < EventMachine::Connection
|
6
|
+
|
7
|
+
include ExperellaProxy::Globals
|
8
|
+
|
9
|
+
# @!visibility private
|
10
|
+
attr_accessor :plexer, :name
|
11
|
+
|
12
|
+
# Called by the EventMachine loop when a remote TCP connection attempt completes successfully
|
13
|
+
#
|
14
|
+
# Calls client {Connection} {Connection#connected} method
|
15
|
+
#
|
16
|
+
def connection_completed
|
17
|
+
log.debug [@name, :conn_complete]
|
18
|
+
@plexer.connected(@name)
|
19
|
+
@connected.succeed
|
20
|
+
end
|
21
|
+
|
22
|
+
# Called by the EventMachine loop whenever data has been received by the network connection.
|
23
|
+
# It is never called by user code. {#receive_data} is called with a single parameter,
|
24
|
+
# a String containing the network protocol data, which may of course be binary.
|
25
|
+
#
|
26
|
+
# Data gets passed to client {Connection} through {Connection#relay_from_backend}
|
27
|
+
#
|
28
|
+
# @param data [String] Opaque response data
|
29
|
+
def receive_data(data)
|
30
|
+
log.debug [:receive_backend, @name, data]
|
31
|
+
@plexer.relay_from_backend(@name, data)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Buffer data for send until the connection to the backend server is established and is ready for use.
|
35
|
+
#
|
36
|
+
# @param data [String] data to be send to the connected backend server
|
37
|
+
def send(data)
|
38
|
+
log.debug [:send_backend, data]
|
39
|
+
@connected.callback { send_data data }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Notify upstream plexer that the backend server is done processing the request
|
43
|
+
#
|
44
|
+
def unbind
|
45
|
+
log.debug [@name, :unbind]
|
46
|
+
@plexer.unbind_backend(@name)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# @private constructor, gets called by EventMachine::Connection's overwritten new method
|
52
|
+
#
|
53
|
+
def initialize
|
54
|
+
@connected = EM::DefaultDeferrable.new
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|