experella-proxy 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,4 @@
1
1
  module ExperellaProxy
2
-
3
2
  # static getter for the connection_manager variable
4
3
  #
5
4
  # @return [ConnectionManager] connection_manager
@@ -9,13 +8,12 @@ module ExperellaProxy
9
8
 
10
9
  # The ConnectionManager is responsible for queueing and matching frontend {Connection} and {BackendServer} objects
11
10
  class ConnectionManager
12
-
13
11
  # The constructor
14
12
  #
15
13
  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
14
+ @connection_queue = [] # array queue of client connection objects
15
+ @backend_queue = [] # array queue of available backend servers
16
+ @backend_list = {} # list of all backend servers
19
17
  end
20
18
 
21
19
  # Matches {Request} to queued {BackendServer}
@@ -34,16 +32,16 @@ module ExperellaProxy
34
32
  def backend_available?(request)
35
33
  @backend_queue.each do |backend|
36
34
  if backend.accept?(request)
37
- #connect backend to requests connection if request matches
35
+ # connect backend to requests connection if request matches
38
36
  backend.workload += 1
39
37
  ret = @backend_queue.delete(backend)
40
- #requeue backend if concurrency isnt maxed
38
+ # requeue backend if concurrency isnt maxed
41
39
  @backend_queue.push(backend) if backend.workload < backend.concurrency
42
40
  return ret
43
41
  end
44
42
  end
45
43
  if match_any_backend?(request)
46
- #push requests connection on queue if no backend was connected
44
+ # push requests connection on queue if no backend was connected
47
45
  @connection_queue.push(request.conn)
48
46
  :queued
49
47
  else
@@ -58,14 +56,14 @@ module ExperellaProxy
58
56
  # @param backend [BackendServer] BackendServer which got free
59
57
  # @return [NilClass]
60
58
  def free_backend(backend)
61
- #check if any queued connections match new available backend
59
+ # check if any queued connections match new available backend
62
60
  conn = match_connections(backend)
63
61
  if conn
64
- #return matching connection
65
- #you should try to connect the new backend to this connection
62
+ # return matching connection
63
+ # you should try to connect the new backend to this connection
66
64
  return conn
67
65
  else
68
- #push free backend on queue if it wasn't used for a queued conn or is already queued (concurrency)
66
+ # push free backend on queue if it wasn't used for a queued conn or is already queued (concurrency)
69
67
  @backend_queue.push(backend) if @backend_list.include?(backend.name) && !@backend_queue.include?(backend)
70
68
  backend.workload -= 1
71
69
  end
@@ -78,17 +76,16 @@ module ExperellaProxy
78
76
  # @return [Connection] a queued connection that would match the BackendServer
79
77
  # @return [Boolean] true if backend was added to list
80
78
  def add_backend(backend)
81
-
82
79
  @backend_list[backend.name] = backend
83
80
 
84
- #check if any queued connections match new available backend
81
+ # check if any queued connections match new available backend
85
82
  conn = match_connections(backend)
86
83
  if conn
87
- #return matching connection
88
- #you should try to connect the new backend to this connection
84
+ # return matching connection
85
+ # you should try to connect the new backend to this connection
89
86
  return conn
90
87
  else
91
- #queue new backend
88
+ # queue new backend
92
89
  @backend_queue.push(backend)
93
90
  end
94
91
  true
@@ -99,7 +96,6 @@ module ExperellaProxy
99
96
  # @param backend [BackendServer] the BackendServer to be removed
100
97
  # @return [Boolean] true if a backend was removed, else returns false
101
98
  def remove_backend(backend)
102
-
103
99
  ret = @backend_list.delete(backend.name)
104
100
  @backend_queue.delete(backend)
105
101
 
@@ -138,7 +134,7 @@ module ExperellaProxy
138
134
  @connection_queue.size
139
135
  end
140
136
 
141
- private
137
+ private
142
138
 
143
139
  # Matches request to all known backends
144
140
  #
@@ -162,6 +158,5 @@ module ExperellaProxy
162
158
  end
163
159
  nil
164
160
  end
165
-
166
161
  end
167
- end
162
+ end
@@ -1,14 +1,12 @@
1
1
  module ExperellaProxy
2
-
3
2
  # defined hop by hop header fields
4
- HOP_HEADERS = ["Connection", "Keep-Alive", "Proxy-Authorization", "TE", "Trailer", "Transfer-Encoding", "Upgrade"]
3
+ HOP_HEADERS = %w(Connection Keep-Alive Proxy-Authorization TE Trailer Transfer-Encoding Upgrade)
5
4
 
6
5
  # Provides getters for global variables
7
6
  #
8
7
  # All methods are private. The module needs to be included in every Class which needs it.
9
8
  module Globals
10
-
11
- private
9
+ private
12
10
 
13
11
  # @!visibility public
14
12
 
@@ -25,8 +23,8 @@ module ExperellaProxy
25
23
  # @param [Hash] details contains details of the event
26
24
  # see ExperellaProxy::Configuration#on_event
27
25
 
28
- def event(name,details={})
29
- config.on_event.call(name,details)
26
+ def event(name, details={})
27
+ config.on_event.call(name, details)
30
28
  end
31
29
 
32
30
  # Get the global connection manager
@@ -40,4 +38,4 @@ module ExperellaProxy
40
38
  config.logger
41
39
  end
42
40
  end
43
- end
41
+ end
@@ -1,45 +1,44 @@
1
1
  module ExperellaProxy
2
-
3
2
  # Every standard HTTP code mapped to the appropriate message.
4
3
  #
5
4
  # @author Mongrel.
6
5
  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'
6
+ 100 => 'Continue',
7
+ 101 => 'Switching Protocols',
8
+ 200 => 'OK',
9
+ 201 => 'Created',
10
+ 202 => 'Accepted',
11
+ 203 => 'Non-Authoritative Information',
12
+ 204 => 'No Content',
13
+ 205 => 'Reset Content',
14
+ 206 => 'Partial Content',
15
+ 300 => 'Multiple Choices',
16
+ 301 => 'Moved Permanently',
17
+ 302 => 'Moved Temporarily',
18
+ 303 => 'See Other',
19
+ 304 => 'Not Modified',
20
+ 305 => 'Use Proxy',
21
+ 400 => 'Bad Request',
22
+ 401 => 'Unauthorized',
23
+ 402 => 'Payment Required',
24
+ 403 => 'Forbidden',
25
+ 404 => 'Not Found',
26
+ 405 => 'Method Not Allowed',
27
+ 406 => 'Not Acceptable',
28
+ 407 => 'Proxy Authentication Required',
29
+ 408 => 'Request Time-out',
30
+ 409 => 'Conflict',
31
+ 410 => 'Gone',
32
+ 411 => 'Length Required',
33
+ 412 => 'Precondition Failed',
34
+ 413 => 'Request Entity Too Large',
35
+ 414 => 'Request-URI Too Large',
36
+ 415 => 'Unsupported Media Type',
37
+ 500 => 'Internal Server Error',
38
+ 501 => 'Not Implemented',
39
+ 502 => 'Bad Gateway',
40
+ 503 => 'Service Unavailable',
41
+ 504 => 'Gateway Time-out',
42
+ 505 => 'HTTP Version not supported'
44
43
  }
45
44
  end
@@ -11,8 +11,7 @@ module ExperellaProxy
11
11
  # @param options [Hash] option Hash passed to the {Connection}
12
12
  # @param blk [Block] Block evaluated in each new {Connection}
13
13
  def self.start(options, &blk)
14
-
15
- #initalize backend servers from config
14
+ # initalize backend servers from config
16
15
  config.backends.each do |backend|
17
16
  connection_manager.add_backend(BackendServer.new(backend[:host], backend[:port], backend))
18
17
  logger.info "Initializing backend #{backend[:name]} at #{backend[:host]}:#{backend[:port]} with concurrency\
@@ -21,11 +20,11 @@ module ExperellaProxy
21
20
  logger.info "Backend mangles: #{backend[:mangle].inspect}"
22
21
  end
23
22
 
24
- #start eventmachine
23
+ # start eventmachine
25
24
  EM.epoll
26
25
  EM.run do
27
- trap("TERM") { stop }
28
- trap("INT") { stop }
26
+ trap("TERM"){ stop }
27
+ trap("INT"){ stop }
29
28
 
30
29
  if config.proxy.empty?
31
30
  logger.fatal "No proxy host:port address configured. Stopping experella-proxy."
@@ -37,10 +36,10 @@ module ExperellaProxy
37
36
  unless proxy[:options].nil?
38
37
  opts = options.merge(proxy[:options])
39
38
  end
40
- logger.info "Launching experella-proxy at #{proxy[:host]}:#{proxy[:port]} with #{config.timeout}s timeout..."
39
+ logger.info "Launching experella-proxy (#{ExperellaProxy::VERSION}) at #{proxy[:host]}:#{proxy[:port]} with #{config.timeout}s timeout..."
41
40
  logger.info "with options: #{opts.inspect}"
42
- EventMachine::start_server(proxy[:host], proxy[:port],
43
- Connection, opts) do |conn|
41
+ EventMachine.start_server(proxy[:host], proxy[:port],
42
+ Connection, opts) do |conn|
44
43
  conn.instance_eval(&blk)
45
44
  end
46
45
  end
@@ -53,7 +52,7 @@ module ExperellaProxy
53
52
  #
54
53
  def self.stop
55
54
  if EM.reactor_running?
56
- EventMachine::stop_event_loop
55
+ EventMachine.stop_event_loop
57
56
  end
58
57
  end
59
58
  end
@@ -5,7 +5,6 @@ module ExperellaProxy
5
5
  # Every Request belongs to a client {Connection}
6
6
  #
7
7
  class Request
8
-
9
8
  include ExperellaProxy::Globals
10
9
 
11
10
  attr_accessor :keep_alive, :chunked
@@ -18,9 +17,9 @@ module ExperellaProxy
18
17
  @conn = conn
19
18
  @header = {}
20
19
  @chunked = false # if true the parsed body will be chunked
21
- @uri = {} #contains port, path and query information for faster backend selection
20
+ @uri = {} # contains port, path and query information for faster backend selection
22
21
  @keep_alive = true
23
- @send_buffer = String.new
22
+ @send_buffer = ''
24
23
  @response = Response.new(self)
25
24
  end
26
25
 
@@ -64,21 +63,21 @@ module ExperellaProxy
64
63
  # First Header after Startline will always be "Host: ", after that order is determined by {#header}.each
65
64
  #
66
65
  def reconstruct_header
67
- #split send_buffer into header and body part
66
+ # split send_buffer into header and body part
68
67
  buf = @send_buffer.split(/\r\n\r\n/, 2) unless flushed?
69
68
  @send_buffer = ""
70
- #start line
69
+ # start line
71
70
  @send_buffer << @header[:http_method] + ' '
72
71
  @send_buffer << @header[:request_url] + ' '
73
72
  @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
73
+ @send_buffer << "Host: " + @header[:Host] + "\r\n" # add Host first for better header readability
74
+ # header fields
76
75
  @header.each do |key, value|
77
- unless key == :http_method || key == :request_url || key == :http_version || key == :Host #exclude startline parameters
76
+ unless key == :http_method || key == :request_url || key == :http_version || key == :Host # exclude startline parameters
78
77
  @send_buffer << key.to_s + ": "
79
78
  if value.is_a?(Array)
80
79
  @send_buffer << value.shift
81
- until value.empty? do
80
+ until value.empty?
82
81
  @send_buffer << "," + value.shift
83
82
  end
84
83
  else
@@ -88,8 +87,8 @@ module ExperellaProxy
88
87
  end
89
88
  end
90
89
  @send_buffer << "\r\n"
91
- #reconstruction complete
92
- @send_buffer << buf[1] unless buf.nil? #append buffered body
90
+ # reconstruction complete
91
+ @send_buffer << buf[1] unless buf.nil? # append buffered body
93
92
  event(:request_reconstruct_header, :data => @send_buffer)
94
93
  end
95
94
 
@@ -99,8 +98,8 @@ module ExperellaProxy
99
98
  #
100
99
  # @param hsh [Hash] hash with HTTP header Key:Value pairs
101
100
  def update_header(hsh)
102
- hsh = hsh.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
101
+ hsh = hsh.reduce({}){ |memo, (k, v)| memo[k.to_sym] = v; memo }
103
102
  @header.update(hsh)
104
103
  end
105
104
  end
106
- end
105
+ end
@@ -5,7 +5,6 @@ module ExperellaProxy
5
5
  # Every Response belongs to a request {Request}
6
6
  #
7
7
  class Response
8
-
9
8
  include ExperellaProxy::Globals
10
9
 
11
10
  attr_reader :header
@@ -18,12 +17,12 @@ module ExperellaProxy
18
17
  @conn = request.conn
19
18
  @header = {}
20
19
  @status_code = 500
21
- @no_length = false #set true if no content-length or transfer-encoding given
22
- @keep_parsing = true #used for special no length case
20
+ @no_length = false # set true if no content-length or transfer-encoding given
21
+ @keep_parsing = true # used for special no length case
23
22
  @chunked = false # if true the parsed body will be chunked
24
23
  @buffer = false # default is false, so incoming data will be streamed,
25
24
  # used for http1.0 clients and transfer-encoding chunked backend responses
26
- @send_buffer = String.new
25
+ @send_buffer = ''
27
26
  @response_parser = Http::Parser.new
28
27
  init_http_parser
29
28
  end
@@ -36,33 +35,29 @@ module ExperellaProxy
36
35
  #
37
36
  # @param str [String] data as string
38
37
  def <<(str)
39
- begin
40
- if @keep_parsing
41
- offset = @response_parser << str
42
-
43
- #edge case for message without content-length and transfer encoding
44
- @conn.send_data str[offset..-1] unless @keep_parsing
45
- else
46
- @conn.send_data str
47
- end
48
-
49
- rescue Http::Parser::Error
50
- event(:response_add, :signature => @conn.signature, :error => true,
51
- :description => "parser error caused by invalid response data")
52
- # on error unbind response_parser object, so additional data doesn't get parsed anymore
53
- #
54
- # assigning a string to the parser variable, will cause incoming data to get buffered
55
- # imho this is a better solution than adding a condition for this rare error case
56
- @response_parser = ""
57
- @conn.close
38
+ if @keep_parsing
39
+ offset = (@response_parser << str)
40
+ # edge case for message without content-length and transfer encoding
41
+ @conn.send_data str[offset..-1] unless @keep_parsing
42
+ else
43
+ @conn.send_data str
58
44
  end
45
+ rescue Http::Parser::Error
46
+ event(:response_add, :signature => @conn.signature, :error => true,
47
+ :description => "parser error caused by invalid response data")
48
+ # on error unbind response_parser object, so additional data doesn't get parsed anymore
49
+ #
50
+ # assigning a string to the parser variable, will cause incoming data to get buffered
51
+ # imho this is a better solution than adding a condition for this rare error case
52
+ @response_parser = ""
53
+ @conn.close
59
54
  end
60
55
 
61
56
  # Returns the data in send_buffer and empties the send_buffer
62
57
  #
63
58
  # @return [String] data to send
64
59
  def flush
65
- event(:response_flush,:data => @send_buffer)
60
+ event(:response_flush, :data => @send_buffer)
66
61
  @send_buffer.slice!(0, @send_buffer.length)
67
62
  end
68
63
 
@@ -81,16 +76,16 @@ module ExperellaProxy
81
76
  #
82
77
  def reconstruct_header
83
78
  @send_buffer = ""
84
- #start line
79
+ # start line
85
80
  @send_buffer << "HTTP/1.1 "
86
81
  @send_buffer << @status_code.to_s + ' '
87
82
  @send_buffer << HTTP_STATUS_CODES[@status_code] + "\r\n"
88
- #header fields
83
+ # header fields
89
84
  @header.each do |key, value|
90
85
  @send_buffer << key.to_s + ": "
91
86
  if value.is_a?(Array)
92
87
  @send_buffer << value.shift
93
- until value.empty? do
88
+ until value.empty?
94
89
  @send_buffer << "," + value.shift
95
90
  end
96
91
  else
@@ -99,7 +94,7 @@ module ExperellaProxy
99
94
  @send_buffer << "\r\n"
100
95
  end
101
96
  @send_buffer << "\r\n"
102
- #reconstruction complete
97
+ # reconstruction complete
103
98
  event(:response_reconstruct_header, :data => @send_buffer)
104
99
  end
105
100
 
@@ -109,15 +104,15 @@ module ExperellaProxy
109
104
  #
110
105
  # @param hsh [Hash] hash with HTTP header Key:Value pairs
111
106
  def update_header(hsh)
112
- hsh = hsh.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
107
+ hsh = hsh.reduce({}){ |memo, (k, v)| memo[k.to_sym] = v; memo }
113
108
  @header.update(hsh)
114
109
  end
115
110
 
116
- private
111
+ private
117
112
 
118
113
  # initializes the response http parser
119
114
  def init_http_parser
120
- #called when response headers are completely parsed (first \r\n\r\n triggers this)
115
+ # called when response headers are completely parsed (first \r\n\r\n triggers this)
121
116
  @response_parser.on_headers_complete = proc do |h|
122
117
 
123
118
  @status_code = @response_parser.status_code
@@ -142,7 +137,7 @@ module ExperellaProxy
142
137
  @no_length = true
143
138
  @header[:Connection] = "close"
144
139
  end
145
- #chunked encoded
140
+ # chunked encoded
146
141
  else
147
142
  # buffer response data if client uses http 1.0 until message complete
148
143
  if @request.header[:http_version][0] == 1 && @request.header[:http_version][1] == 0
@@ -168,7 +163,6 @@ module ExperellaProxy
168
163
  h.delete(s)
169
164
  end
170
165
 
171
-
172
166
  via = h.delete("Via")
173
167
  if via.nil?
174
168
  via = "1.1 experella"
@@ -219,4 +213,4 @@ module ExperellaProxy
219
213
  end
220
214
  end
221
215
  end
222
- end
216
+ end
@@ -7,7 +7,7 @@ module ExperellaProxy
7
7
  #
8
8
  # @param options [Hash] options Hash passed to the proxy
9
9
  def initialize(options)
10
- @options=options
10
+ @options = options
11
11
  end
12
12
 
13
13
  attr_reader :options
@@ -25,7 +25,6 @@ module ExperellaProxy
25
25
  # {Connection#unbind} in on_unbind
26
26
  #
27
27
  def run
28
-
29
28
  Proxy.start(options = {}) do |conn|
30
29
  event(:server_new_connection, :msec => msec, :signature => signature)
31
30
 
@@ -58,10 +57,6 @@ module ExperellaProxy
58
57
 
59
58
  end
60
59
  end
61
-
62
60
  end
63
-
64
61
  end
65
-
66
62
  end
67
-
@@ -1,5 +1,9 @@
1
1
  module ExperellaProxy
2
2
  # ExperellaProxy Gemversion
3
+ # 0.0.11
4
+ # * output version on start
5
+ # * rubocup config file
6
+ # * applied rubyocop config file
3
7
  # 0.0.10
4
8
  # * no logging any more just firing events
5
9
  # 0.0.9
@@ -23,5 +27,5 @@ module ExperellaProxy
23
27
  # * added self-signed SSL certificate for TLS/HTTPS
24
28
  # * added config template init functionality
25
29
  #
26
- VERSION = "0.0.10"
30
+ VERSION = "0.0.11"
27
31
  end
@@ -1,6 +1,7 @@
1
1
  require 'optparse'
2
2
  require 'eventmachine'
3
3
  require 'http_parser.rb'
4
+ require 'experella-proxy/version'
4
5
  require 'experella-proxy/globals'
5
6
  require 'experella-proxy/http_status_codes'
6
7
  require 'experella-proxy/configuration'
@@ -35,7 +36,6 @@ require 'experella-proxy/response'
35
36
  # @see file:README.md README
36
37
  # @author Dennis-Florian Herr 2014 @Experteer GmbH
37
38
  module ExperellaProxy
38
-
39
39
  # Initializes ExperellaProxy's {Configuration} and {ConnectionManager}
40
40
  #
41
41
  # @param [Hash] options Hash passed to the configuration
@@ -43,11 +43,11 @@ module ExperellaProxy
43
43
  # @return [Boolean] true if successful false if NoConfigError was raised
44
44
  def self.init(options={})
45
45
  begin
46
- Configuration.new(options)
47
- rescue Configuration::NoConfigError => e
48
- puts e.message
49
- puts e.backtrace.join("\n\t")
50
- return false
46
+ Configuration.new(options)
47
+ rescue Configuration::NoConfigError => e
48
+ puts e.message
49
+ puts e.backtrace.join("\n\t")
50
+ return false
51
51
  end
52
52
  @connection_manager = ConnectionManager.new
53
53
  true
@@ -66,19 +66,18 @@ module ExperellaProxy
66
66
  # Loses all buffered data
67
67
  def self.restart
68
68
  opts = @server.options
69
- self.stop
69
+ stop
70
70
  Server.new(opts).run if ExperellaProxy.init(opts)
71
71
  end
72
72
 
73
73
  # Stops ExperellaProxy
74
74
  #
75
75
  def self.stop
76
- Proxy.stop
76
+ Proxy.stop
77
77
  end
78
-
79
78
  end
80
79
 
81
- #startup
80
+ # startup
82
81
  ARGV << '--help' if ARGV.empty?
83
82
 
84
83
  options = {}
@@ -1,10 +1,9 @@
1
1
  require 'eventmachine'
2
2
  require 'http_parser.rb'
3
3
  module EchoServer
4
-
5
4
  def post_init
6
5
  @parser = Http::Parser.new
7
- @buffer = String.new
6
+ @buffer = ''
8
7
 
9
8
  @parser.on_headers_complete = proc do |h|
10
9
  if @parser.request_path == "/chunked"
@@ -30,15 +29,14 @@ module EchoServer
30
29
  end
31
30
  end
32
31
 
33
- def receive_data data
32
+ def receive_data(data)
34
33
  @buffer << data
35
34
  @parser << data
36
35
  end
37
-
38
36
  end
39
37
 
40
38
  EventMachine.run do
41
- trap("QUIT") { EM.stop }
39
+ trap("QUIT"){ EM.stop }
42
40
 
43
41
  if ARGV.count == 2
44
42
  EventMachine.start_server ARGV.first, ARGV.last.to_i, EchoServer
@@ -46,4 +44,4 @@ EventMachine.run do
46
44
  raise "invalid number of params, expected [server] [port]"
47
45
  end
48
46
 
49
- end
47
+ end