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.
Files changed (43) hide show
  1. data/.gitignore +15 -0
  2. data/Gemfile +3 -0
  3. data/README.md +219 -0
  4. data/Rakefile +25 -0
  5. data/TODO.txt +20 -0
  6. data/bin/experella-proxy +54 -0
  7. data/config/default/404.html +16 -0
  8. data/config/default/503.html +18 -0
  9. data/config/default/config.rb +64 -0
  10. data/config/default/ssl/certs/experella-proxy.pem +18 -0
  11. data/config/default/ssl/private/experella-proxy.key +28 -0
  12. data/dev/experella-proxy +62 -0
  13. data/experella-proxy.gemspec +39 -0
  14. data/lib/experella-proxy/backend.rb +58 -0
  15. data/lib/experella-proxy/backend_server.rb +100 -0
  16. data/lib/experella-proxy/configuration.rb +154 -0
  17. data/lib/experella-proxy/connection.rb +557 -0
  18. data/lib/experella-proxy/connection_manager.rb +167 -0
  19. data/lib/experella-proxy/globals.rb +37 -0
  20. data/lib/experella-proxy/http_status_codes.rb +45 -0
  21. data/lib/experella-proxy/proxy.rb +61 -0
  22. data/lib/experella-proxy/request.rb +106 -0
  23. data/lib/experella-proxy/response.rb +204 -0
  24. data/lib/experella-proxy/server.rb +68 -0
  25. data/lib/experella-proxy/version.rb +15 -0
  26. data/lib/experella-proxy.rb +93 -0
  27. data/spec/echo-server/echo_server.rb +49 -0
  28. data/spec/experella-proxy/backend_server_spec.rb +101 -0
  29. data/spec/experella-proxy/configuration_spec.rb +27 -0
  30. data/spec/experella-proxy/connection_manager_spec.rb +159 -0
  31. data/spec/experella-proxy/experella-proxy_spec.rb +471 -0
  32. data/spec/experella-proxy/request_spec.rb +88 -0
  33. data/spec/experella-proxy/response_spec.rb +44 -0
  34. data/spec/fixtures/404.html +16 -0
  35. data/spec/fixtures/503.html +18 -0
  36. data/spec/fixtures/spec.log +331 -0
  37. data/spec/fixtures/test_config.rb +34 -0
  38. data/spec/spec.log +235 -0
  39. data/spec/spec_helper.rb +35 -0
  40. data/test/sinatra/hello_world_server.rb +17 -0
  41. data/test/sinatra/server_one.rb +89 -0
  42. data/test/sinatra/server_two.rb +89 -0
  43. metadata +296 -0
@@ -0,0 +1,167 @@
1
+ module ExperellaProxy
2
+
3
+ # static getter for the connection_manager variable
4
+ #
5
+ # @return [ConnectionManager] connection_manager
6
+ def self.connection_manager
7
+ @connection_manager
8
+ end
9
+
10
+ # The ConnectionManager is responsible for queueing and matching frontend {Connection} and {BackendServer} objects
11
+ class ConnectionManager
12
+
13
+ # The constructor
14
+ #
15
+ def initialize
16
+ @connection_queue = [] #array queue of client connection objects
17
+ @backend_queue = [] #array queue of available backend servers
18
+ @backend_list = {} #list of all backend servers
19
+ end
20
+
21
+ # Matches {Request} to queued {BackendServer}
22
+ #
23
+ # Removes first matching {BackendServer} from queue and returns it.
24
+ # It will requeue the {BackendServer} instantly,
25
+ # if {BackendServer#workload} is smaller than {BackendServer#concurrency}
26
+ #
27
+ # Queues {Request#conn} if no available {BackendServer} matches
28
+ #
29
+ # Returns false if no registered {BackendServer} matches
30
+ #
31
+ # @return [BackendServer] first matching BackendServer from the queue
32
+ # @return [Symbol] :queued if Connection was queued
33
+ # @return [Boolean] false if no registered Backend matches the Request
34
+ def backend_available?(request)
35
+ @backend_queue.each do |backend|
36
+ if backend.accept?(request)
37
+ #connect backend to requests connection if request matches
38
+ backend.workload += 1
39
+ ret = @backend_queue.delete(backend)
40
+ #requeue backend if concurrency isnt maxed
41
+ @backend_queue.push(backend) if backend.workload < backend.concurrency
42
+ return ret
43
+ end
44
+ end
45
+ if match_any_backend?(request)
46
+ #push requests connection on queue if no backend was connected
47
+ @connection_queue.push(request.conn)
48
+ :queued
49
+ else
50
+ false
51
+ end
52
+ end
53
+
54
+ # Called by a {Connection} when the {BackendServer} is done.
55
+ #
56
+ # Connects backend to a matching queued {Connection} or pushes server back on queue
57
+ #
58
+ # @param backend [BackendServer] BackendServer which got free
59
+ # @return [NilClass]
60
+ def free_backend(backend)
61
+ #check if any queued connections match new available backend
62
+ conn = match_connections(backend)
63
+ if conn
64
+ #return matching connection
65
+ #you should try to connect the new backend to this connection
66
+ return conn
67
+ else
68
+ #push free backend on queue if it wasn't used for a queued conn or is already queued (concurrency)
69
+ @backend_queue.push(backend) if @backend_list.include?(backend.name) && !@backend_queue.include?(backend)
70
+ backend.workload -= 1
71
+ end
72
+ nil
73
+ end
74
+
75
+ # Adds a new {BackendServer} to the list and queues or connects it
76
+ #
77
+ # @param backend [BackendServer] a new BackendServer
78
+ # @return [Connection] a queued connection that would match the BackendServer
79
+ # @return [Boolean] true if backend was added to list
80
+ def add_backend(backend)
81
+
82
+ @backend_list[backend.name] = backend
83
+
84
+ #check if any queued connections match new available backend
85
+ conn = match_connections(backend)
86
+ if conn
87
+ #return matching connection
88
+ #you should try to connect the new backend to this connection
89
+ return conn
90
+ else
91
+ #queue new backend
92
+ @backend_queue.push(backend)
93
+ end
94
+ true
95
+ end
96
+
97
+ # Removes a {BackendServer} from list and queue
98
+ #
99
+ # @param backend [BackendServer] the BackendServer to be removed
100
+ # @return [Boolean] true if a backend was removed, else returns false
101
+ def remove_backend(backend)
102
+
103
+ ret = @backend_list.delete(backend.name)
104
+ @backend_queue.delete(backend)
105
+
106
+ if ret
107
+ true
108
+ else
109
+ false
110
+ end
111
+ end
112
+
113
+ # Removes a connection from the connection_queue
114
+ #
115
+ # @param conn [Connection] Connection to be removed
116
+ def free_connection(conn)
117
+ @connection_queue.delete(conn)
118
+ end
119
+
120
+ # returns the count of the currently queued {BackendServer}s
121
+ #
122
+ # @return [int]
123
+ def backend_queue_count
124
+ @backend_queue.size
125
+ end
126
+
127
+ # returns the count of the registered{BackendServer}s
128
+ #
129
+ # @return [int]
130
+ def backend_count
131
+ @backend_list.size
132
+ end
133
+
134
+ # returns the count of the currently queued connections
135
+ #
136
+ # @return [int]
137
+ def connection_count
138
+ @connection_queue.size
139
+ end
140
+
141
+ private
142
+
143
+ # Matches request to all known backends
144
+ #
145
+ # @return [Boolean] true if it can be matched, false if request is not accepted at all
146
+ def match_any_backend?(request)
147
+ @backend_list.each_value do |v|
148
+ return true if v.accept?(request)
149
+ end
150
+ false
151
+ end
152
+
153
+ # Matches queued connections with a backend
154
+ #
155
+ # @return [Connection] matching connection
156
+ # @return [NilClass] nothing matched
157
+ def match_connections(backend)
158
+ @connection_queue.each do |conn|
159
+ if backend.accept?(conn.get_request)
160
+ return conn
161
+ end
162
+ end
163
+ nil
164
+ end
165
+
166
+ end
167
+ end
@@ -0,0 +1,37 @@
1
+ module ExperellaProxy
2
+
3
+ # defined hop by hop header fields
4
+ HOP_HEADERS = ["Connection", "Keep-Alive", "Proxy-Authorization", "TE", "Trailer", "Transfer-Encoding", "Upgrade"]
5
+
6
+ # Provides getters for global variables
7
+ #
8
+ # All methods are private. The module needs to be included in every Class which needs it.
9
+ module Globals
10
+
11
+ private
12
+
13
+ # @!visibility public
14
+
15
+ # Get the global config
16
+ #
17
+ # @return [Configuration] config object
18
+ def config
19
+ ExperellaProxy.config
20
+ end
21
+
22
+ # Get the global logger
23
+ #
24
+ # @return [Logger] logger set in config object
25
+ def log
26
+ ExperellaProxy.config.logger
27
+ end
28
+
29
+ # Get the global connection manager
30
+ #
31
+ # @return [ConnectionManager] connection_manager object
32
+ def connection_manager
33
+ ExperellaProxy.connection_manager
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ module ExperellaProxy
2
+
3
+ # Every standard HTTP code mapped to the appropriate message.
4
+ #
5
+ # @author Mongrel.
6
+ HTTP_STATUS_CODES = {
7
+ 100 => 'Continue',
8
+ 101 => 'Switching Protocols',
9
+ 200 => 'OK',
10
+ 201 => 'Created',
11
+ 202 => 'Accepted',
12
+ 203 => 'Non-Authoritative Information',
13
+ 204 => 'No Content',
14
+ 205 => 'Reset Content',
15
+ 206 => 'Partial Content',
16
+ 300 => 'Multiple Choices',
17
+ 301 => 'Moved Permanently',
18
+ 302 => 'Moved Temporarily',
19
+ 303 => 'See Other',
20
+ 304 => 'Not Modified',
21
+ 305 => 'Use Proxy',
22
+ 400 => 'Bad Request',
23
+ 401 => 'Unauthorized',
24
+ 402 => 'Payment Required',
25
+ 403 => 'Forbidden',
26
+ 404 => 'Not Found',
27
+ 405 => 'Method Not Allowed',
28
+ 406 => 'Not Acceptable',
29
+ 407 => 'Proxy Authentication Required',
30
+ 408 => 'Request Time-out',
31
+ 409 => 'Conflict',
32
+ 410 => 'Gone',
33
+ 411 => 'Length Required',
34
+ 412 => 'Precondition Failed',
35
+ 413 => 'Request Entity Too Large',
36
+ 414 => 'Request-URI Too Large',
37
+ 415 => 'Unsupported Media Type',
38
+ 500 => 'Internal Server Error',
39
+ 501 => 'Not Implemented',
40
+ 502 => 'Bad Gateway',
41
+ 503 => 'Service Unavailable',
42
+ 504 => 'Gateway Time-out',
43
+ 505 => 'HTTP Version not supported'
44
+ }
45
+ end
@@ -0,0 +1,61 @@
1
+ module ExperellaProxy
2
+ # The proxy
3
+ #
4
+ # Controls the EventMachine, initializes backends from config and starts proxy servers
5
+ class Proxy
6
+ extend ExperellaProxy::Globals
7
+
8
+ # Starts the Eventmachine, initializes backends in {ConnectionManager} and starts the servers
9
+ # defined in config the proxy should listen on
10
+ #
11
+ # @param options [Hash] option Hash passed to the {Connection}
12
+ # @param blk [Block] Block evaluated in each new {Connection}
13
+ def self.start(options, &blk)
14
+
15
+ #initalize backend servers from config
16
+ config.backends.each do |backend|
17
+ connection_manager.add_backend(BackendServer.new(backend[:host], backend[:port], backend))
18
+ log.info "Initializing backend #{backend[:name]} at #{backend[:host]}:#{backend[:port]} with concurrency\
19
+ #{backend[:concurrency]}"
20
+ log.info "Backend accepts: #{backend[:accepts].inspect}"
21
+ log.info "Backend mangles: #{backend[:mangle].inspect}"
22
+ end
23
+
24
+ #start eventmachine
25
+ EM.epoll
26
+ EM.run do
27
+ trap("TERM") { stop }
28
+ trap("INT") { stop }
29
+
30
+ if config.proxy.empty?
31
+ log.fatal "No proxy host:port address configured. Stopping experella-proxy."
32
+ return stop
33
+ else
34
+ config.proxy.each do |proxy|
35
+ opts = options
36
+ # pass proxy specific options
37
+ unless proxy[:options].nil?
38
+ opts = options.merge(proxy[:options])
39
+ end
40
+ log.info "Launching experella-proxy at #{proxy[:host]}:#{proxy[:port]} with #{config.timeout}s timeout..."
41
+ log.info "with options: #{opts.inspect}"
42
+ EventMachine::start_server(proxy[:host], proxy[:port],
43
+ Connection, opts) do |conn|
44
+ conn.instance_eval(&blk)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ #
52
+ # Stops the Eventmachine and terminates all connections
53
+ #
54
+ def self.stop
55
+ if EM.reactor_running?
56
+ log.info("Terminating experella-proxy")
57
+ EventMachine::stop_event_loop
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,106 @@
1
+ module ExperellaProxy
2
+ #
3
+ # Request is used to store incoming (HTTP) requests and parsed data
4
+ #
5
+ # Every Request belongs to a client {Connection}
6
+ #
7
+ class Request
8
+
9
+ include ExperellaProxy::Globals
10
+
11
+ attr_accessor :keep_alive, :chunked
12
+ attr_reader :conn, :header, :uri, :response
13
+
14
+ # The constructor
15
+ #
16
+ # @param conn [Connection] Connection the request belongs to
17
+ def initialize(conn)
18
+ @conn = conn
19
+ @header = {}
20
+ @chunked = false # if true the parsed body will be chunked
21
+ @uri = {} #contains port, path and query information for faster backend selection
22
+ @keep_alive = true
23
+ @send_buffer = String.new
24
+ @response = Response.new(self)
25
+ end
26
+
27
+ # Adds data to the request object
28
+ #
29
+ # data must be formatted as string
30
+ #
31
+ # @param str [String] data as string
32
+ def <<(str)
33
+ @send_buffer << str
34
+ end
35
+
36
+ # Adds a hash with uri information to {#uri}
37
+ #
38
+ # duplicate key values will be overwritten with hsh values
39
+ #
40
+ # @param hsh [Hash] hash with keys :port :path :query containing URI information
41
+ def add_uri(hsh)
42
+ @uri.update(hsh)
43
+ log.debug hsh
44
+ end
45
+
46
+ # Returns the data in send_buffer and empties the send_buffer
47
+ #
48
+ # @return [String] data to send
49
+ def flush
50
+ @send_buffer.slice!(0, @send_buffer.length)
51
+ end
52
+
53
+ # Returns if the send_buffer is flushed? (empty)
54
+ #
55
+ # @return [Boolean]
56
+ def flushed?
57
+ @send_buffer.empty?
58
+ end
59
+
60
+ # Reconstructs modified http request in send_buffer
61
+ #
62
+ # Reconstructed request must be a valid request according to the HTTP Protocol
63
+ #
64
+ # First Header after Startline will always be "Host: ", after that order is determined by {#header}.each
65
+ #
66
+ def reconstruct_header
67
+ #split send_buffer into header and body part
68
+ buf = @send_buffer.split(/\r\n\r\n/, 2) unless flushed?
69
+ @send_buffer = ""
70
+ #start line
71
+ @send_buffer << @header[:http_method] + ' '
72
+ @send_buffer << @header[:request_url] + ' '
73
+ @send_buffer << "HTTP/1.1\r\n"
74
+ @send_buffer << "Host: " + @header[:Host] + "\r\n" #add Host first for better header readability
75
+ #header fields
76
+ @header.each do |key, value|
77
+ unless key == :http_method || key == :request_url || key == :http_version || key == :Host #exclude startline parameters
78
+ @send_buffer << key.to_s + ": "
79
+ if value.is_a?(Array)
80
+ @send_buffer << value.shift
81
+ until value.empty? do
82
+ @send_buffer << "," + value.shift
83
+ end
84
+ else
85
+ @send_buffer << value
86
+ end
87
+ @send_buffer << "\r\n"
88
+ end
89
+ end
90
+ @send_buffer << "\r\n"
91
+ #reconstruction complete
92
+ @send_buffer << buf[1] unless buf.nil? #append buffered body
93
+ log.debug [:reconstructed_sendbuffer, @send_buffer]
94
+ end
95
+
96
+ # Adds a hash to {#header}
97
+ #
98
+ # symbolizes hsh keys, duplicate key values will be overwritten with hsh values
99
+ #
100
+ # @param hsh [Hash] hash with HTTP header Key:Value pairs
101
+ def update_header(hsh)
102
+ hsh = hsh.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
103
+ @header.update(hsh)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,204 @@
1
+ module ExperellaProxy
2
+ #
3
+ # Response is used to store incoming (HTTP) responses and parsed data
4
+ #
5
+ # Every Response belongs to a request {Request}
6
+ #
7
+ class Response
8
+
9
+ include ExperellaProxy::Globals
10
+
11
+ attr_reader :header
12
+
13
+ # The constructor
14
+ #
15
+ # @param request [Request] Request the response belongs to
16
+ def initialize(request)
17
+ @request = request
18
+ @conn = request.conn
19
+ @header = {}
20
+ @status_code = 500
21
+ @chunked = false # if true the parsed body will be chunked
22
+ @buffer = false # default is false, so incoming data will be streamed,
23
+ # used for http1.0 clients and transfer-encoding chunked backend responses
24
+ @send_buffer = String.new
25
+ @response_parser = Http::Parser.new
26
+ init_http_parser
27
+ end
28
+
29
+ # Adds data to the response object
30
+ #
31
+ # data must be formatted as string
32
+ #
33
+ # On Http::Parser::Error parsing gets interrupted and the connection closed
34
+ #
35
+ # @param str [String] data as string
36
+ def <<(str)
37
+ begin
38
+ @response_parser << str
39
+ rescue Http::Parser::Error
40
+ log.warn ["Parser error caused by invalid response data", "@#{@conn.signature}"]
41
+ # on error unbind response_parser object, so additional data doesn't get parsed anymore
42
+ #
43
+ # assigning a string to the parser variable, will cause incoming data to get buffered
44
+ # imho this is a better solution than adding a condition for this rare error case
45
+ @response_parser = ""
46
+ @conn.close
47
+ end
48
+ end
49
+
50
+ # Returns the data in send_buffer and empties the send_buffer
51
+ #
52
+ # @return [String] data to send
53
+ def flush
54
+ log.debug [:data_to_user, @send_buffer]
55
+ @send_buffer.slice!(0, @send_buffer.length)
56
+ end
57
+
58
+ # Returns if the send_buffer is flushed? (empty)
59
+ #
60
+ # @return [Boolean]
61
+ def flushed?
62
+ @send_buffer.empty?
63
+ end
64
+
65
+ # Reconstructs modified http response in send_buffer
66
+ #
67
+ # Reconstructed response must be a valid response according to the HTTP Protocol
68
+ #
69
+ # Header order is determined by {#header}.each
70
+ #
71
+ def reconstruct_header
72
+ @send_buffer = ""
73
+ #start line
74
+ @send_buffer << "HTTP/1.1 "
75
+ @send_buffer << @status_code.to_s + ' '
76
+ @send_buffer << HTTP_STATUS_CODES[@status_code] + "\r\n"
77
+ #header fields
78
+ @header.each do |key, value|
79
+ @send_buffer << key.to_s + ": "
80
+ if value.is_a?(Array)
81
+ @send_buffer << value.shift
82
+ until value.empty? do
83
+ @send_buffer << "," + value.shift
84
+ end
85
+ else
86
+ @send_buffer << value
87
+ end
88
+ @send_buffer << "\r\n"
89
+ end
90
+ @send_buffer << "\r\n"
91
+ #reconstruction complete
92
+ log.debug [:response_reconstructed_header, @send_buffer]
93
+ end
94
+
95
+ # Adds a hash to {#header}
96
+ #
97
+ # symbolizes hsh keys, duplicate key values will be overwritten with hsh values
98
+ #
99
+ # @param hsh [Hash] hash with HTTP header Key:Value pairs
100
+ def update_header(hsh)
101
+ hsh = hsh.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
102
+ @header.update(hsh)
103
+ end
104
+
105
+ private
106
+
107
+ # initializes the response http parser
108
+ def init_http_parser
109
+ #called when response headers are completely parsed (first \r\n\r\n triggers this)
110
+ @response_parser.on_headers_complete = proc do |h|
111
+
112
+ @status_code = @response_parser.status_code
113
+
114
+ if @request.keep_alive
115
+ @header[:Connection] = "Keep-Alive"
116
+ end
117
+
118
+ # handle the transfer-encoding
119
+ #
120
+ # if no transfer encoding and no content-length is given, terminate connection after backend unbind
121
+ #
122
+ # if no transfer encoding is given, but there is content-length, just keep the content-length and send the message
123
+ #
124
+ # if a transfer-encoding is given, continue with Transfer-Encoding chunked and remove false content-length
125
+ # header if present. Old Transfer-Encoding header will be removed with all other hop-by-hop headers
126
+ #
127
+ if h["Transfer-Encoding"].nil?
128
+ # if no transfer-encoding and no content-length is present, set Connection: close
129
+ if h["Content-Length"].nil?
130
+ @request.keep_alive = false
131
+ @header[:Connection] = "close"
132
+ end
133
+ #chunked encoded
134
+ else
135
+ # buffer response data if client uses http 1.0 until message complete
136
+ if @request.header[:http_version][0] == 1 && @request.header[:http_version][1] == 0
137
+ @buffer = true
138
+ else
139
+ h.delete("Content-Length")
140
+ @chunked = true unless @request.header[:http_method] == "HEAD"
141
+ @header[:"Transfer-Encoding"] = "chunked"
142
+ end
143
+ end
144
+
145
+ # remove all hop-by-hop header fields
146
+ unless h["Connection"].nil?
147
+ h["Connection"].each do |s|
148
+ h.delete(s)
149
+ end
150
+ end
151
+ HOP_HEADERS.each do |s|
152
+ h.delete(s)
153
+ end
154
+
155
+
156
+ via = h.delete("Via")
157
+ if via.nil?
158
+ via = "1.1 experella"
159
+ else
160
+ via << "1.1 experella"
161
+ end
162
+ @header[:Via] = via
163
+
164
+
165
+ update_header(h)
166
+ unless @buffer
167
+ # called before any data is put into send_buffer
168
+ reconstruct_header
169
+ @conn.send_data flush
170
+ end
171
+ end
172
+
173
+ @response_parser.on_body = proc do |chunk|
174
+ if @chunked
175
+ # add hexadecimal chunk size
176
+ @send_buffer << chunk.size.to_s(16)
177
+ @send_buffer << "\r\n"
178
+ @send_buffer << chunk
179
+ @send_buffer << "\r\n"
180
+ else
181
+ @send_buffer << chunk
182
+ end
183
+ unless @buffer
184
+ @conn.send_data flush
185
+ end
186
+ end
187
+
188
+ @response_parser.on_message_complete = proc do
189
+ if @chunked
190
+ # send closing chunk
191
+ @send_buffer << "0\r\n\r\n"
192
+ @conn.send_data flush
193
+ elsif @buffer
194
+ @header[:"Content-Length"] = @send_buffer.size.to_s
195
+ body = flush
196
+ reconstruct_header
197
+ @send_buffer << body
198
+ @conn.send_data flush
199
+ end
200
+ end
201
+
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,68 @@
1
+ module ExperellaProxy
2
+ # The server starts the {Proxy} and provides callbacks/block hooks for client {Connection}s
3
+ class Server
4
+ include ExperellaProxy::Globals
5
+
6
+ # Constructor
7
+ #
8
+ # @param options [Hash] options Hash passed to the proxy
9
+ def initialize(options)
10
+ @options=options
11
+ end
12
+
13
+ attr_reader :options
14
+
15
+ # Runs the proxy server with given options
16
+ #
17
+ # Opens a block passed to every {Connection}
18
+ #
19
+ # You can add logic to
20
+ #
21
+ # {Connection#connected} in on_connect
22
+ # {Connection#receive_data} in on_data, must return data
23
+ # {Connection#relay_from_backend} in on_response, must return resp
24
+ # {Connection#unbind_backend} in on_finish
25
+ # {Connection#unbind} in on_unbind
26
+ #
27
+ def run
28
+
29
+ Proxy.start(options = {}) do |conn|
30
+
31
+ log.info msec + "new Connection @" + signature.to_s
32
+
33
+ # called on successful backend connection
34
+ # backend is the name of the connected server
35
+ conn.on_connect do |backend|
36
+
37
+ end
38
+
39
+ # modify / process request stream
40
+ # and return modified data
41
+ conn.on_data do |data|
42
+ data
43
+ end
44
+
45
+ # modify / process response stream
46
+ # and return modified response
47
+ conn.on_response do |backend, resp|
48
+ resp
49
+ end
50
+
51
+ # termination logic
52
+ conn.on_finish do |backend|
53
+
54
+ end
55
+
56
+ # called if client terminates connection
57
+ # or timeout occurs
58
+ conn.on_unbind do
59
+
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
@@ -0,0 +1,15 @@
1
+ module ExperellaProxy
2
+ # ExperellaProxy Gemversion
3
+ # 0.0.6
4
+ # * updated homepage
5
+ # 0.0.5
6
+ # * added :host_port option to backend configuration
7
+ # 0.0.4
8
+ # * added lambda for accept filtering
9
+ #
10
+ # 0.0.3
11
+ # * added self-signed SSL certificate for TLS/HTTPS
12
+ # * added config template init functionality
13
+ #
14
+ VERSION = "0.0.6"
15
+ end